Adding a hash type to CipherSuite (#24)
This commit is contained in:
+62
-44
@@ -10,6 +10,7 @@ use crate::{
|
||||
envelope::{Envelope, ExportKeySize},
|
||||
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
|
||||
group::Group,
|
||||
hash::Hash,
|
||||
key_exchange::traits::{KeyExchange, ToBytes},
|
||||
keypair::{Key, KeyPair, SizedBytes},
|
||||
oprf,
|
||||
@@ -87,17 +88,18 @@ where
|
||||
|
||||
/// The final message from the client, containing sealed cryptographic
|
||||
/// identifiers
|
||||
pub struct RegisterThirdMessage<KeyFormat: KeyPair> {
|
||||
pub struct RegisterThirdMessage<KeyFormat: KeyPair, D: Hash> {
|
||||
/// The "envelope" generated by the user, containing sealed
|
||||
/// cryptographic identifiers
|
||||
envelope: Envelope,
|
||||
envelope: Envelope<D>,
|
||||
/// The user's public key
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
}
|
||||
|
||||
impl<KeyFormat> RegisterThirdMessage<KeyFormat>
|
||||
impl<KeyFormat, D> RegisterThirdMessage<KeyFormat, D>
|
||||
where
|
||||
KeyFormat: KeyPair,
|
||||
D: Hash,
|
||||
{
|
||||
/// byte representation for the registration upload message
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -105,15 +107,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<KeyFormat> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat>
|
||||
impl<KeyFormat, D> TryFrom<&[u8]> for RegisterThirdMessage<KeyFormat, D>
|
||||
where
|
||||
KeyFormat: KeyPair,
|
||||
D: Hash,
|
||||
{
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn try_from(third_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let key_len = <KeyFormat::Repr as SizedBytes>::Len::to_usize();
|
||||
let envelope_size = key_len + Envelope::additional_size();
|
||||
let envelope_size = key_len + Envelope::<D>::additional_size();
|
||||
let checked_bytes = check_slice_size(
|
||||
third_message_bytes,
|
||||
envelope_size + key_len,
|
||||
@@ -123,7 +126,7 @@ where
|
||||
let client_s_pk = KeyFormat::check_public_key(unchecked_client_s_pk)?;
|
||||
|
||||
Ok(Self {
|
||||
envelope: Envelope::from_bytes(&checked_bytes[..envelope_size])?,
|
||||
envelope: Envelope::<D>::from_bytes(&checked_bytes[..envelope_size])?,
|
||||
client_s_pk,
|
||||
})
|
||||
}
|
||||
@@ -133,7 +136,7 @@ where
|
||||
pub struct LoginFirstMessage<CS: CipherSuite> {
|
||||
/// blinded password information
|
||||
alpha: CS::Group,
|
||||
ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message,
|
||||
ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1Message,
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
|
||||
@@ -145,7 +148,7 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
|
||||
let arr = GenericArray::from_slice(&first_message_bytes[..elem_len]);
|
||||
let alpha = CS::Group::from_element_slice(arr)?;
|
||||
|
||||
let ke1_message = <CS::KeyExchange as KeyExchange>::KE1Message::try_from(
|
||||
let ke1_message = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1Message::try_from(
|
||||
first_message_bytes[elem_len..].to_vec(),
|
||||
)?;
|
||||
Ok(Self { alpha, ke1_message })
|
||||
@@ -161,25 +164,27 @@ impl<CS: CipherSuite> LoginFirstMessage<CS> {
|
||||
|
||||
/// The answer sent by the server to the user, upon reception of the
|
||||
/// login attempt.
|
||||
pub struct LoginSecondMessage<Grp, KeyFormat, KE>
|
||||
pub struct LoginSecondMessage<Grp, KeyFormat, KE, D>
|
||||
where
|
||||
KeyFormat: KeyPair<Repr = Key>,
|
||||
KE: KeyExchange,
|
||||
KE: KeyExchange<D>,
|
||||
D: Hash,
|
||||
{
|
||||
_key_format: PhantomData<KeyFormat>,
|
||||
_key_exchange: PhantomData<KE>,
|
||||
/// the server's oprf output
|
||||
beta: Grp,
|
||||
/// the user's sealed information,
|
||||
envelope: Envelope,
|
||||
envelope: Envelope<D>,
|
||||
ke2_message: KE::KE2Message,
|
||||
}
|
||||
|
||||
impl<Grp, KeyFormat, KE> LoginSecondMessage<Grp, KeyFormat, KE>
|
||||
impl<Grp, KeyFormat, KE, D> LoginSecondMessage<Grp, KeyFormat, KE, D>
|
||||
where
|
||||
Grp: Group,
|
||||
KeyFormat: KeyPair<Repr = Key>,
|
||||
KE: KeyExchange,
|
||||
KE: KeyExchange<D>,
|
||||
D: Hash,
|
||||
{
|
||||
/// byte representation for the login response
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
@@ -192,16 +197,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Grp, KeyFormat, KE> TryFrom<&[u8]> for LoginSecondMessage<Grp, KeyFormat, KE>
|
||||
impl<Grp, KeyFormat, KE, D> TryFrom<&[u8]> for LoginSecondMessage<Grp, KeyFormat, KE, D>
|
||||
where
|
||||
Grp: Group,
|
||||
KeyFormat: KeyPair<Repr = Key>,
|
||||
KE: KeyExchange,
|
||||
KE: KeyExchange<D>,
|
||||
D: Hash,
|
||||
{
|
||||
type Error = ProtocolError;
|
||||
fn try_from(second_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let key_len = <KeyFormat::Repr as SizedBytes>::Len::to_usize();
|
||||
let envelope_size = key_len + Envelope::additional_size();
|
||||
let envelope_size = key_len + Envelope::<D>::additional_size();
|
||||
let elem_len = Grp::ElemLen::to_usize();
|
||||
let ke2_message_size = KE::ke2_message_size();
|
||||
let checked_slice = check_slice_size(
|
||||
@@ -216,7 +222,8 @@ where
|
||||
let arr = GenericArray::from_slice(beta_bytes);
|
||||
let beta = Grp::from_element_slice(arr)?;
|
||||
|
||||
let envelope = Envelope::from_bytes(&checked_slice[elem_len..elem_len + envelope_size])?;
|
||||
let envelope =
|
||||
Envelope::<D>::from_bytes(&checked_slice[elem_len..elem_len + envelope_size])?;
|
||||
|
||||
let ke2_message =
|
||||
KE::KE2Message::try_from(checked_slice[elem_len + envelope_size..].to_vec())?;
|
||||
@@ -234,14 +241,15 @@ where
|
||||
/// The answer sent by the client to the server, upon reception of the
|
||||
/// sealed envelope
|
||||
pub struct LoginThirdMessage<CS: CipherSuite> {
|
||||
ke3_message: <CS::KeyExchange as KeyExchange>::KE3Message,
|
||||
ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE3Message,
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginThirdMessage<CS> {
|
||||
type Error = ProtocolError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let ke3_message = <CS::KeyExchange as KeyExchange>::KE3Message::try_from(bytes.to_vec())?;
|
||||
let ke3_message =
|
||||
<CS::KeyExchange as KeyExchange<CS::Hash>>::KE3Message::try_from(bytes.to_vec())?;
|
||||
Ok(Self { ke3_message })
|
||||
}
|
||||
}
|
||||
@@ -310,6 +318,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut rng = OsRng;
|
||||
@@ -336,8 +345,8 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
}
|
||||
}
|
||||
|
||||
type ClientRegistrationFinishResult<KeyFormat> = (
|
||||
RegisterThirdMessage<KeyFormat>,
|
||||
type ClientRegistrationFinishResult<KeyFormat, D> = (
|
||||
RegisterThirdMessage<KeyFormat, D>,
|
||||
GenericArray<u8, ExportKeySize>,
|
||||
);
|
||||
|
||||
@@ -361,6 +370,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -378,16 +388,16 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
r2: RegisterSecondMessage<CS::Group>,
|
||||
server_s_pk: &<CS::KeyFormat as KeyPair>::Repr,
|
||||
rng: &mut R,
|
||||
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat>, ProtocolError> {
|
||||
) -> Result<ClientRegistrationFinishResult<CS::KeyFormat, CS::Hash>, ProtocolError> {
|
||||
let client_static_keypair = CS::KeyFormat::generate_random(rng)?;
|
||||
|
||||
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash>(
|
||||
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(
|
||||
self.password.clone(),
|
||||
r2.beta,
|
||||
&self.blinding_factor,
|
||||
)?;
|
||||
|
||||
let (envelope, export_key) = Envelope::seal(
|
||||
let (envelope, export_key) = Envelope::<CS::Hash>::seal(
|
||||
&password_derived_key,
|
||||
&client_static_keypair.private().to_arr(),
|
||||
&server_s_pk.to_arr(),
|
||||
@@ -434,7 +444,7 @@ impl<CS: CipherSuite> Drop for ClientLogin<CS> {
|
||||
|
||||
/// The state elements the server holds to record a registration
|
||||
pub struct ServerRegistration<CS: CipherSuite> {
|
||||
envelope: Option<Envelope>,
|
||||
envelope: Option<Envelope<CS::Hash>>,
|
||||
client_s_pk: Option<<CS::KeyFormat as KeyPair>::Repr>,
|
||||
pub(crate) oprf_key: <CS::Group as Group>::Scalar,
|
||||
}
|
||||
@@ -452,7 +462,7 @@ where
|
||||
fn try_from(server_registration_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let key_len = <<CS::KeyFormat as KeyPair>::Repr as SizedBytes>::Len::to_usize();
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
|
||||
let envelope_size = key_len + Envelope::additional_size();
|
||||
let envelope_size = key_len + Envelope::<CS::Hash>::additional_size();
|
||||
|
||||
if server_registration_bytes.len() == scalar_len {
|
||||
return Ok(Self {
|
||||
@@ -476,7 +486,7 @@ where
|
||||
)?;
|
||||
let client_s_pk = CS::KeyFormat::check_public_key(unchecked_client_s_pk)?;
|
||||
Ok(Self {
|
||||
envelope: Some(Envelope::from_bytes(
|
||||
envelope: Some(Envelope::<CS::Hash>::from_bytes(
|
||||
&checked_bytes[checked_bytes.len() - envelope_size..],
|
||||
)?),
|
||||
client_s_pk: Some(client_s_pk),
|
||||
@@ -526,6 +536,7 @@ where
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -573,6 +584,7 @@ where
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -588,7 +600,7 @@ where
|
||||
/// ```
|
||||
pub fn finish(
|
||||
self,
|
||||
message: RegisterThirdMessage<CS::KeyFormat>,
|
||||
message: RegisterThirdMessage<CS::KeyFormat, CS::Hash>,
|
||||
) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
envelope: Some(message.envelope),
|
||||
@@ -610,7 +622,7 @@ pub struct ClientLogin<CS: CipherSuite> {
|
||||
blinding_factor: <CS::Group as Group>::Scalar,
|
||||
/// The user's password
|
||||
password: Vec<u8>,
|
||||
ke1_state: <CS::KeyExchange as KeyExchange>::KE1State,
|
||||
ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1State,
|
||||
}
|
||||
|
||||
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||
@@ -619,8 +631,8 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
|
||||
let blinding_factor_bytes = GenericArray::from_slice(&bytes[..scalar_len]);
|
||||
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
|
||||
let ke1_state_size = <CS::KeyExchange as KeyExchange>::ke1_state_size();
|
||||
let ke1_state = <CS::KeyExchange as KeyExchange>::KE1State::try_from(
|
||||
let ke1_state_size = <CS::KeyExchange as KeyExchange<CS::Hash>>::ke1_state_size();
|
||||
let ke1_state = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1State::try_from(
|
||||
bytes[scalar_len..scalar_len + ke1_state_size].to_vec(),
|
||||
)?;
|
||||
let password = bytes[scalar_len + ke1_state_size..].to_vec();
|
||||
@@ -670,6 +682,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -722,6 +735,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -738,19 +752,19 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
/// ```
|
||||
pub fn finish<R: RngCore + CryptoRng>(
|
||||
self,
|
||||
l2: LoginSecondMessage<CS::Group, CS::KeyFormat, CS::KeyExchange>,
|
||||
l2: LoginSecondMessage<CS::Group, CS::KeyFormat, CS::KeyExchange, CS::Hash>,
|
||||
server_s_pk: &<<CS as CipherSuite>::KeyFormat as KeyPair>::Repr,
|
||||
_client_e_sk_rng: &mut R,
|
||||
) -> Result<ClientLoginFinishResult<CS>, ProtocolError> {
|
||||
let l2_bytes: Vec<u8> = [&l2.beta.to_arr()[..], &l2.envelope.to_bytes()].concat();
|
||||
|
||||
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash>(
|
||||
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(
|
||||
self.password.clone(),
|
||||
l2.beta,
|
||||
&self.blinding_factor,
|
||||
)?;
|
||||
|
||||
let (client_s_sk, export_key) = &l2
|
||||
let opened_envelope = &l2
|
||||
.envelope
|
||||
.open(&password_derived_key, &server_s_pk.to_arr())
|
||||
.map_err(|e| match e {
|
||||
@@ -763,20 +777,20 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
l2.ke2_message,
|
||||
&self.ke1_state,
|
||||
server_s_pk.clone(),
|
||||
Key::from_bytes(client_s_sk)?,
|
||||
Key::from_bytes(&opened_envelope.plaintext)?,
|
||||
)?;
|
||||
|
||||
Ok((
|
||||
LoginThirdMessage { ke3_message },
|
||||
shared_secret,
|
||||
*export_key,
|
||||
opened_envelope.export_key,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// The state elements the server holds to record a login
|
||||
pub struct ServerLogin<CS: CipherSuite> {
|
||||
ke2_state: <CS::KeyExchange as KeyExchange>::KE2State,
|
||||
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE2State,
|
||||
_cs: PhantomData<CS>,
|
||||
}
|
||||
|
||||
@@ -785,7 +799,9 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ServerLogin<CS> {
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
_cs: PhantomData,
|
||||
ke2_state: <CS::KeyExchange as KeyExchange>::KE2State::try_from(bytes.to_vec())?,
|
||||
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash>>::KE2State::try_from(
|
||||
bytes.to_vec(),
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -795,6 +811,7 @@ type ServerLoginStartResult<CS> = (
|
||||
<CS as CipherSuite>::Group,
|
||||
<CS as CipherSuite>::KeyFormat,
|
||||
<CS as CipherSuite>::KeyExchange,
|
||||
<CS as CipherSuite>::Hash,
|
||||
>,
|
||||
ServerLogin<CS>,
|
||||
);
|
||||
@@ -825,6 +842,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -901,6 +919,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
/// type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||
/// type KeyFormat = opaque_ke::keypair::X25519KeyPair;
|
||||
/// type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||
/// type Hash = sha2::Sha256;
|
||||
/// type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||
/// }
|
||||
/// let mut client_rng = OsRng;
|
||||
@@ -918,24 +937,23 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
/// # Ok::<(), ProtocolError>(())
|
||||
/// ```
|
||||
pub fn finish(&self, message: LoginThirdMessage<CS>) -> Result<Vec<u8>, ProtocolError> {
|
||||
<CS::KeyExchange as KeyExchange>::finish_ke(message.ke3_message, &self.ke2_state).map_err(
|
||||
|e| match e {
|
||||
<CS::KeyExchange as KeyExchange<CS::Hash>>::finish_ke(message.ke3_message, &self.ke2_state)
|
||||
.map_err(|e| match e {
|
||||
ProtocolError::VerificationError(PakeError::KeyExchangeMacValidationError) => {
|
||||
ProtocolError::VerificationError(PakeError::InvalidLoginError)
|
||||
}
|
||||
err => err,
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
fn get_password_derived_key<G: Group, SH: SlowHash>(
|
||||
fn get_password_derived_key<G: Group, SH: SlowHash<D>, D: Hash>(
|
||||
password: Vec<u8>,
|
||||
beta: G,
|
||||
blinding_factor: &G::Scalar,
|
||||
) -> Result<Vec<u8>, InternalPakeError> {
|
||||
let oprf_output = oprf::generate_oprf3::<G>(&password, beta, blinding_factor)?;
|
||||
let oprf_output = oprf::generate_oprf3::<G, D>(&password, beta, blinding_factor)?;
|
||||
SH::hash(oprf_output)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user