Updating AKE message format (#85)
This commit is contained in:
+4
-4
@@ -155,9 +155,9 @@ impl<D: Hash> Envelope<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let nonce = &input[..NONCE_LEN];
|
let nonce = &input[..NONCE_LEN];
|
||||||
let (ciphertext, remainder) = tokenize(input[NONCE_LEN..].to_vec(), 2)?;
|
let (ciphertext, remainder) = tokenize(&input[NONCE_LEN..], 2)?;
|
||||||
let (auth_data, remainder) = tokenize(remainder, 2)?;
|
let (auth_data, remainder) = tokenize(&remainder, 2)?;
|
||||||
let (hmac, remainder) = tokenize(remainder, 2)?;
|
let (hmac, remainder) = tokenize(&remainder, 2)?;
|
||||||
Ok((
|
Ok((
|
||||||
Self::new(
|
Self::new(
|
||||||
nonce.to_vec(),
|
nonce.to_vec(),
|
||||||
@@ -195,7 +195,7 @@ impl<D: Hash> Envelope<D> {
|
|||||||
while !bytes_copy.is_empty() {
|
while !bytes_copy.is_empty() {
|
||||||
let t = u8_to_credential_type(bytes_copy[0])
|
let t = u8_to_credential_type(bytes_copy[0])
|
||||||
.ok_or(InternalPakeError::IncompatibleEnvelopeCredentialsError)?;
|
.ok_or(InternalPakeError::IncompatibleEnvelopeCredentialsError)?;
|
||||||
let (cred, remainder) = tokenize(bytes_copy[1..].to_vec(), 2)
|
let (cred, remainder) = tokenize(&bytes_copy[1..], 2)
|
||||||
.map_err(|_| InternalPakeError::IncompatibleEnvelopeCredentialsError)?;
|
.map_err(|_| InternalPakeError::IncompatibleEnvelopeCredentialsError)?;
|
||||||
bytes_copy = remainder;
|
bytes_copy = remainder;
|
||||||
credentials.insert(t, cred);
|
credentials.insert(t, cred);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// LICENSE file in the root directory of this source tree.
|
// LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{InternalPakeError, ProtocolError},
|
errors::{PakeError, ProtocolError},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
keypair::KeyPair,
|
keypair::KeyPair,
|
||||||
};
|
};
|
||||||
@@ -13,17 +13,19 @@ use rand_core::{CryptoRng, RngCore};
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||||
type KE1State: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
type KE1State: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||||
type KE2State: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
type KE2State: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||||
type KE1Message: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
type KE1Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||||
type KE2Message: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
type KE2Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||||
type KE3Message: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
type KE3Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||||
|
|
||||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||||
l1_component: Vec<u8>,
|
l1_component: Vec<u8>,
|
||||||
|
info: Vec<u8>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
|
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn generate_ke2<R: RngCore + CryptoRng>(
|
fn generate_ke2<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
l1_bytes: Vec<u8>,
|
l1_bytes: Vec<u8>,
|
||||||
@@ -31,6 +33,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
|||||||
ke1_message: Self::KE1Message,
|
ke1_message: Self::KE1Message,
|
||||||
client_s_pk: KeyFormat::Repr,
|
client_s_pk: KeyFormat::Repr,
|
||||||
server_s_sk: KeyFormat::Repr,
|
server_s_sk: KeyFormat::Repr,
|
||||||
|
info: Vec<u8>,
|
||||||
|
e_info: Vec<u8>,
|
||||||
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError>;
|
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError>;
|
||||||
|
|
||||||
fn generate_ke3(
|
fn generate_ke3(
|
||||||
@@ -39,6 +43,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
|||||||
ke1_state: &Self::KE1State,
|
ke1_state: &Self::KE1State,
|
||||||
server_s_pk: KeyFormat::Repr,
|
server_s_pk: KeyFormat::Repr,
|
||||||
client_s_sk: KeyFormat::Repr,
|
client_s_sk: KeyFormat::Repr,
|
||||||
|
info: Vec<u8>,
|
||||||
|
e_info: Vec<u8>,
|
||||||
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError>;
|
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError>;
|
||||||
|
|
||||||
fn finish_ke(
|
fn finish_ke(
|
||||||
|
|||||||
+121
-49
@@ -5,11 +5,14 @@
|
|||||||
|
|
||||||
//! An implementation of the Triple Diffie-Hellman key exchange protocol
|
//! An implementation of the Triple Diffie-Hellman key exchange protocol
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
|
errors::{
|
||||||
|
utils::{check_slice_size, check_slice_size_atleast},
|
||||||
|
InternalPakeError, PakeError, ProtocolError,
|
||||||
|
},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
key_exchange::traits::{KeyExchange, ToBytes},
|
key_exchange::traits::{KeyExchange, ToBytes},
|
||||||
keypair::{KeyPair, SizedBytesExt},
|
keypair::{KeyPair, SizedBytesExt},
|
||||||
serialization::serialize,
|
serialization::{serialize, tokenize},
|
||||||
};
|
};
|
||||||
use digest::{Digest, FixedOutput};
|
use digest::{Digest, FixedOutput};
|
||||||
use generic_array::{
|
use generic_array::{
|
||||||
@@ -47,6 +50,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
|
|
||||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||||
l1_component: Vec<u8>,
|
l1_component: Vec<u8>,
|
||||||
|
info: Vec<u8>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
|
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
|
||||||
let client_e_kp = KeyFormat::generate_random(rng)?;
|
let client_e_kp = KeyFormat::generate_random(rng)?;
|
||||||
@@ -58,6 +62,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
|
|
||||||
let ke1_message = KE1Message {
|
let ke1_message = KE1Message {
|
||||||
client_nonce,
|
client_nonce,
|
||||||
|
info,
|
||||||
client_e_pk: client_e_kp.public().clone(),
|
client_e_pk: client_e_kp.public().clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,6 +88,8 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
ke1_message: Self::KE1Message,
|
ke1_message: Self::KE1Message,
|
||||||
client_s_pk: KeyFormat::Repr,
|
client_s_pk: KeyFormat::Repr,
|
||||||
server_s_sk: KeyFormat::Repr,
|
server_s_sk: KeyFormat::Repr,
|
||||||
|
info: Vec<u8>,
|
||||||
|
e_info: Vec<u8>,
|
||||||
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError> {
|
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError> {
|
||||||
let server_e_kp = KeyFormat::generate_random(rng)?;
|
let server_e_kp = KeyFormat::generate_random(rng)?;
|
||||||
let server_nonce: GenericArray<u8, NonceLen> = {
|
let server_nonce: GenericArray<u8, NonceLen> = {
|
||||||
@@ -102,8 +109,8 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
},
|
},
|
||||||
&ke1_message.client_nonce,
|
&ke1_message.client_nonce,
|
||||||
&server_nonce,
|
&server_nonce,
|
||||||
client_s_pk,
|
&client_s_pk.to_arr(),
|
||||||
KeyFormat::public_from_private(&server_s_sk),
|
&KeyFormat::public_from_private(&server_s_sk).to_arr(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut hasher = D::new();
|
let mut hasher = D::new();
|
||||||
@@ -114,16 +121,25 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
&hashed_l1[..],
|
&hashed_l1[..],
|
||||||
&l2_bytes[..],
|
&l2_bytes[..],
|
||||||
&server_nonce[..],
|
&server_nonce[..],
|
||||||
|
&serialize(&info, 2),
|
||||||
&server_e_kp.public().to_arr(),
|
&server_e_kp.public().to_arr(),
|
||||||
|
&serialize(&e_info, 2),
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
let mut hasher2 = D::new();
|
let mut hasher2 = D::new();
|
||||||
hasher2.update(&transcript2);
|
hasher2.update(&transcript2);
|
||||||
let hashed_transcript = hasher2.finalize();
|
let hashed_transcript_without_mac = hasher2.finalize();
|
||||||
|
|
||||||
let mut mac = Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
|
let mut mac_hasher =
|
||||||
mac.update(&hashed_transcript);
|
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
|
||||||
|
mac_hasher.update(&hashed_transcript_without_mac);
|
||||||
|
let mac = mac_hasher.finalize().into_bytes();
|
||||||
|
|
||||||
|
let mut hasher3 = D::new();
|
||||||
|
hasher3.update(&transcript2);
|
||||||
|
hasher3.update(mac.clone());
|
||||||
|
let hashed_transcript = hasher3.finalize();
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
KE2State {
|
KE2State {
|
||||||
@@ -133,8 +149,10 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
},
|
},
|
||||||
KE2Message {
|
KE2Message {
|
||||||
server_nonce,
|
server_nonce,
|
||||||
|
info,
|
||||||
server_e_pk: server_e_kp.public().clone(),
|
server_e_pk: server_e_kp.public().clone(),
|
||||||
mac: mac.finalize().into_bytes(),
|
e_info,
|
||||||
|
mac,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -145,6 +163,8 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
ke1_state: &Self::KE1State,
|
ke1_state: &Self::KE1State,
|
||||||
server_s_pk: KeyFormat::Repr,
|
server_s_pk: KeyFormat::Repr,
|
||||||
client_s_sk: KeyFormat::Repr,
|
client_s_sk: KeyFormat::Repr,
|
||||||
|
info: Vec<u8>,
|
||||||
|
e_info: Vec<u8>,
|
||||||
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError> {
|
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError> {
|
||||||
let (session_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
|
let (session_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
|
||||||
TripleDHComponents {
|
TripleDHComponents {
|
||||||
@@ -157,25 +177,24 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
},
|
},
|
||||||
&ke1_state.client_nonce,
|
&ke1_state.client_nonce,
|
||||||
&ke2_message.server_nonce,
|
&ke2_message.server_nonce,
|
||||||
KeyFormat::public_from_private(&client_s_sk),
|
&KeyFormat::public_from_private(&client_s_sk).to_arr(),
|
||||||
server_s_pk,
|
&server_s_pk.to_arr(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let transcript: Vec<u8> = [
|
let transcript: Vec<u8> = [
|
||||||
&ke1_state.hashed_l1[..],
|
&ke1_state.hashed_l1[..],
|
||||||
&l2_component[..],
|
&l2_component[..],
|
||||||
&ke2_message.server_nonce[..],
|
&ke2_message.to_bytes_without_mac(),
|
||||||
&ke2_message.server_e_pk.to_arr(),
|
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
let mut hasher = D::new();
|
let mut hasher = D::new();
|
||||||
hasher.update(&transcript);
|
hasher.update(&transcript);
|
||||||
let hashed_transcript = hasher.finalize();
|
let hashed_transcript_without_mac = hasher.finalize();
|
||||||
|
|
||||||
let mut server_mac =
|
let mut server_mac =
|
||||||
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
|
Hmac::<D>::new_varkey(&km2).map_err(|_| InternalPakeError::HmacError)?;
|
||||||
server_mac.update(&hashed_transcript);
|
server_mac.update(&hashed_transcript_without_mac);
|
||||||
|
|
||||||
if ke2_message.mac != server_mac.finalize().into_bytes() {
|
if ke2_message.mac != server_mac.finalize().into_bytes() {
|
||||||
return Err(ProtocolError::VerificationError(
|
return Err(ProtocolError::VerificationError(
|
||||||
@@ -183,13 +202,27 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut hasher2 = D::new();
|
||||||
|
hasher2.update(transcript);
|
||||||
|
hasher2.update(ke2_message.mac.to_vec());
|
||||||
|
let hashed_transcript = hasher2.finalize();
|
||||||
|
|
||||||
|
let transcript_with_ke3 = [
|
||||||
|
hashed_transcript.to_vec(),
|
||||||
|
serialize(&info, 2),
|
||||||
|
serialize(&e_info, 2),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
let mut client_mac =
|
let mut client_mac =
|
||||||
Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
|
Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
|
||||||
client_mac.update(&hashed_transcript);
|
client_mac.update(&transcript_with_ke3);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
session_secret.to_vec(),
|
session_secret.to_vec(),
|
||||||
KE3Message {
|
KE3Message {
|
||||||
|
info,
|
||||||
|
e_info,
|
||||||
mac: client_mac.finalize().into_bytes(),
|
mac: client_mac.finalize().into_bytes(),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
@@ -199,9 +232,14 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
|||||||
ke3_message: Self::KE3Message,
|
ke3_message: Self::KE3Message,
|
||||||
ke2_state: &Self::KE2State,
|
ke2_state: &Self::KE2State,
|
||||||
) -> Result<Vec<u8>, ProtocolError> {
|
) -> Result<Vec<u8>, ProtocolError> {
|
||||||
|
let transcript_with_ke3 = [
|
||||||
|
ke2_state.hashed_transcript.to_vec(),
|
||||||
|
ke3_message.to_bytes_without_mac(),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
let mut client_mac =
|
let mut client_mac =
|
||||||
Hmac::<D>::new_varkey(&ke2_state.km3).map_err(|_| InternalPakeError::HmacError)?;
|
Hmac::<D>::new_varkey(&ke2_state.km3).map_err(|_| InternalPakeError::HmacError)?;
|
||||||
client_mac.update(&ke2_state.hashed_transcript);
|
client_mac.update(&transcript_with_ke3);
|
||||||
|
|
||||||
if ke3_message.mac != client_mac.finalize().into_bytes() {
|
if ke3_message.mac != client_mac.finalize().into_bytes() {
|
||||||
return Err(ProtocolError::VerificationError(
|
return Err(ProtocolError::VerificationError(
|
||||||
@@ -233,11 +271,12 @@ pub struct KE1State<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
|||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct KE1Message<KeyFormat: KeyPair> {
|
pub struct KE1Message<KeyFormat: KeyPair> {
|
||||||
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
||||||
|
pub(crate) info: Vec<u8>,
|
||||||
pub(crate) client_e_pk: KeyFormat::Repr,
|
pub(crate) client_e_pk: KeyFormat::Repr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]> for KE1State<HashLen, KeyFormat> {
|
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]> for KE1State<HashLen, KeyFormat> {
|
||||||
type Error = InternalPakeError;
|
type Error = PakeError;
|
||||||
|
|
||||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let checked_bytes = check_slice_size(
|
let checked_bytes = check_slice_size(
|
||||||
@@ -270,20 +309,30 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE1State<HashLen,
|
|||||||
|
|
||||||
impl<KeyFormat: KeyPair> ToBytes for KE1Message<KeyFormat> {
|
impl<KeyFormat: KeyPair> ToBytes for KE1Message<KeyFormat> {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
[&self.client_nonce[..], &self.client_e_pk.to_arr()].concat()
|
[
|
||||||
|
&self.client_nonce[..],
|
||||||
|
&serialize(&self.info, 2),
|
||||||
|
&self.client_e_pk.to_arr(),
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<KeyFormat: KeyPair> TryFrom<&[u8]> for KE1Message<KeyFormat> {
|
impl<KeyFormat: KeyPair> TryFrom<&[u8]> for KE1Message<KeyFormat> {
|
||||||
type Error = InternalPakeError;
|
type Error = PakeError;
|
||||||
|
|
||||||
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let checked_bytes =
|
let checked_nonce =
|
||||||
check_slice_size(ke1_message_bytes, NONCE_LEN + KEY_LEN, "ke1_message")?;
|
check_slice_size_atleast(ke1_message_bytes, NONCE_LEN, "ke1_message nonce")?;
|
||||||
|
|
||||||
|
let (info, remainder) = tokenize(&checked_nonce[NONCE_LEN..], 2)?;
|
||||||
|
|
||||||
|
let checked_client_e_pk = check_slice_size(&remainder, KEY_LEN, "ke1_message client_e_pk")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
client_nonce: GenericArray::clone_from_slice(&checked_bytes[..NONCE_LEN]),
|
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||||
client_e_pk: KeyFormat::Repr::from_bytes(&checked_bytes[NONCE_LEN..])?,
|
info,
|
||||||
|
client_e_pk: KeyFormat::Repr::from_bytes(&checked_client_e_pk)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,27 +346,28 @@ pub struct KE2State<HashLen: ArrayLength<u8>> {
|
|||||||
/// The second key exchange message
|
/// The second key exchange message
|
||||||
pub struct KE2Message<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
pub struct KE2Message<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
||||||
server_nonce: GenericArray<u8, NonceLen>,
|
server_nonce: GenericArray<u8, NonceLen>,
|
||||||
|
info: Vec<u8>,
|
||||||
server_e_pk: KeyFormat::Repr,
|
server_e_pk: KeyFormat::Repr,
|
||||||
|
e_info: Vec<u8>,
|
||||||
mac: GenericArray<u8, HashLen>,
|
mac: GenericArray<u8, HashLen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE2State<HashLen> {
|
impl<HashLen: ArrayLength<u8>> ToBytes for KE2State<HashLen> {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
let output: Vec<u8> = [
|
[
|
||||||
&self.km3[..],
|
&self.km3[..],
|
||||||
&self.hashed_transcript[..],
|
&self.hashed_transcript[..],
|
||||||
&self.session_secret[..],
|
&self.session_secret[..],
|
||||||
]
|
]
|
||||||
.concat();
|
.concat()
|
||||||
output
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2State<HashLen> {
|
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2State<HashLen> {
|
||||||
type Error = InternalPakeError;
|
type Error = PakeError;
|
||||||
|
|
||||||
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let checked_bytes = check_slice_size(ke1_message_bytes, 3 * KEY_LEN, "ke2_state")?;
|
let checked_bytes = check_slice_size(input, 3 * KEY_LEN, "ke2_state")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
km3: GenericArray::clone_from_slice(&checked_bytes[..KEY_LEN]),
|
km3: GenericArray::clone_from_slice(&checked_bytes[..KEY_LEN]),
|
||||||
@@ -329,31 +379,41 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2State<HashLen> {
|
|||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE2Message<HashLen, KeyFormat> {
|
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE2Message<HashLen, KeyFormat> {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
let output: Vec<u8> = [
|
[&self.to_bytes_without_mac(), &self.mac[..]].concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> KE2Message<HashLen, KeyFormat> {
|
||||||
|
fn to_bytes_without_mac(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
&self.server_nonce[..],
|
&self.server_nonce[..],
|
||||||
|
&serialize(&self.info, 2),
|
||||||
&self.server_e_pk.to_arr(),
|
&self.server_e_pk.to_arr(),
|
||||||
&self.mac[..],
|
&serialize(&self.e_info, 2),
|
||||||
]
|
]
|
||||||
.concat();
|
.concat()
|
||||||
output
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
||||||
for KE2Message<HashLen, KeyFormat>
|
for KE2Message<HashLen, KeyFormat>
|
||||||
{
|
{
|
||||||
type Error = InternalPakeError;
|
type Error = PakeError;
|
||||||
|
|
||||||
fn try_from(ke2_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let ke2_message_len = NONCE_LEN + KEY_LEN + HashLen::to_usize();
|
let checked_nonce = check_slice_size_atleast(input, NONCE_LEN, "ke2_message nonce")?;
|
||||||
let checked_bytes = check_slice_size(ke2_message_bytes, ke2_message_len, "ke2_message")?;
|
let (info, remainder) = tokenize(&checked_nonce[NONCE_LEN..], 2)?;
|
||||||
|
let checked_server_e_pk =
|
||||||
|
check_slice_size_atleast(&remainder, KEY_LEN, "ke2_message server_e_pk")?;
|
||||||
|
let (e_info, remainder) = tokenize(&checked_server_e_pk[KEY_LEN..], 2)?;
|
||||||
|
let checked_mac = check_slice_size(&remainder, HashLen::to_usize(), "ke1_message mac")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
server_nonce: GenericArray::clone_from_slice(&checked_bytes[..NONCE_LEN]),
|
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||||
server_e_pk: KeyFormat::Repr::from_bytes(
|
info,
|
||||||
&checked_bytes[NONCE_LEN..NONCE_LEN + KEY_LEN],
|
server_e_pk: KeyFormat::Repr::from_bytes(&checked_server_e_pk[..KEY_LEN])?,
|
||||||
)?,
|
e_info,
|
||||||
mac: GenericArray::clone_from_slice(&checked_bytes[NONCE_LEN + KEY_LEN..]),
|
mac: GenericArray::clone_from_slice(&checked_mac),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,22 +437,34 @@ type TripleDHDerivationResult<D> = (
|
|||||||
|
|
||||||
/// The third key exchange message
|
/// The third key exchange message
|
||||||
pub struct KE3Message<HashLen: ArrayLength<u8>> {
|
pub struct KE3Message<HashLen: ArrayLength<u8>> {
|
||||||
|
info: Vec<u8>,
|
||||||
|
e_info: Vec<u8>,
|
||||||
mac: GenericArray<u8, HashLen>,
|
mac: GenericArray<u8, HashLen>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE3Message<HashLen> {
|
impl<HashLen: ArrayLength<u8>> ToBytes for KE3Message<HashLen> {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
self.mac.to_vec()
|
[self.to_bytes_without_mac(), self.mac.to_vec()].concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<HashLen: ArrayLength<u8>> KE3Message<HashLen> {
|
||||||
|
fn to_bytes_without_mac(&self) -> Vec<u8> {
|
||||||
|
[serialize(&self.info, 2), serialize(&self.e_info, 2)].concat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE3Message<HashLen> {
|
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE3Message<HashLen> {
|
||||||
type Error = InternalPakeError;
|
type Error = PakeError;
|
||||||
|
|
||||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let checked_bytes = check_slice_size(bytes, KEY_LEN, "ke3_message")?;
|
let (info, remainder) = tokenize(&bytes, 2)?;
|
||||||
|
let (e_info, remainder) = tokenize(&remainder, 2)?;
|
||||||
|
let checked_bytes = check_slice_size(&remainder, KEY_LEN, "ke3_message")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
info,
|
||||||
|
e_info,
|
||||||
mac: GenericArray::clone_from_slice(&checked_bytes),
|
mac: GenericArray::clone_from_slice(&checked_bytes),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -406,8 +478,8 @@ fn derive_3dh_keys<KeyFormat: KeyPair, D: Hash>(
|
|||||||
dh: TripleDHComponents<KeyFormat>,
|
dh: TripleDHComponents<KeyFormat>,
|
||||||
client_nonce: &GenericArray<u8, NonceLen>,
|
client_nonce: &GenericArray<u8, NonceLen>,
|
||||||
server_nonce: &GenericArray<u8, NonceLen>,
|
server_nonce: &GenericArray<u8, NonceLen>,
|
||||||
client_s_pk: KeyFormat::Repr,
|
id_u: &[u8],
|
||||||
server_s_pk: KeyFormat::Repr,
|
id_s: &[u8],
|
||||||
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
|
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
|
||||||
let ikm: Vec<u8> = [
|
let ikm: Vec<u8> = [
|
||||||
&KeyFormat::diffie_hellman(dh.pk1, dh.sk1)[..],
|
&KeyFormat::diffie_hellman(dh.pk1, dh.sk1)[..],
|
||||||
@@ -420,8 +492,8 @@ fn derive_3dh_keys<KeyFormat: KeyPair, D: Hash>(
|
|||||||
STR_3DH,
|
STR_3DH,
|
||||||
&serialize(&client_nonce, 2),
|
&serialize(&client_nonce, 2),
|
||||||
&serialize(&server_nonce, 2),
|
&serialize(&server_nonce, 2),
|
||||||
&serialize(&client_s_pk.to_arr(), 2),
|
&serialize(id_u, 2),
|
||||||
&serialize(&server_s_pk.to_arr(), 2),
|
&serialize(id_s, 2),
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
|
|||||||
+26
-18
@@ -81,11 +81,11 @@ impl<Grp: Group> RegisterFirstMessage<Grp> {
|
|||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (data, remainder) = tokenize(input[1..].to_vec(), 3)?;
|
let (data, remainder) = tokenize(&input[1..], 3)?;
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
let (alpha_bytes, remainder) = tokenize(data, 2)?;
|
let (alpha_bytes, remainder) = tokenize(&data, 2)?;
|
||||||
|
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
@@ -191,17 +191,17 @@ where
|
|||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (data, remainder) = tokenize(input[1..].to_vec(), 3)?;
|
let (data, remainder) = tokenize(&input[1..], 3)?;
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (beta_bytes, remainder) = tokenize(data, 2)?;
|
let (beta_bytes, remainder) = tokenize(&data, 2)?;
|
||||||
let (server_s_pk, remainder) = tokenize(remainder, 2)?;
|
let (server_s_pk, remainder) = tokenize(&remainder, 2)?;
|
||||||
|
|
||||||
// Handle ecf deserialization
|
// Handle ecf deserialization
|
||||||
let (secret_credentials, remainder) = tokenize(remainder, 1)?;
|
let (secret_credentials, remainder) = tokenize(&remainder, 1)?;
|
||||||
let (cleartext_credentials, remainder) = tokenize(remainder, 1)?;
|
let (cleartext_credentials, remainder) = tokenize(&remainder, 1)?;
|
||||||
let sc = secret_credentials
|
let sc = secret_credentials
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| u8_to_credential_type(*x).ok_or(PakeError::SerializationError))
|
.map(|x| u8_to_credential_type(*x).ok_or(PakeError::SerializationError))
|
||||||
@@ -291,13 +291,13 @@ where
|
|||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (data, remainder) = tokenize(input[1..].to_vec(), 3)?;
|
let (data, remainder) = tokenize(&input[1..], 3)?;
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (envelope, remainder) = Envelope::<D>::deserialize(&data)?;
|
let (envelope, remainder) = Envelope::<D>::deserialize(&data)?;
|
||||||
let (client_s_pk, remainder) = tokenize(remainder, 2)?;
|
let (client_s_pk, remainder) = tokenize(&remainder, 2)?;
|
||||||
|
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
@@ -348,8 +348,8 @@ impl<CS: CipherSuite> LoginFirstMessage<CS> {
|
|||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (data, ke1m) = tokenize(input[1..].to_vec(), 3)?;
|
let (data, ke1m) = tokenize(&input[1..], 3)?;
|
||||||
let (alpha_bytes, remainder) = tokenize(data, 2)?;
|
let (alpha_bytes, remainder) = tokenize(&data, 2)?;
|
||||||
|
|
||||||
if !remainder.is_empty() {
|
if !remainder.is_empty() {
|
||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
@@ -399,8 +399,8 @@ impl<CS: CipherSuite> LoginSecondMessage<CS> {
|
|||||||
return Err(PakeError::SerializationError.into());
|
return Err(PakeError::SerializationError.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (data, ke2m) = tokenize(input[1..].to_vec(), 3)?;
|
let (data, ke2m) = tokenize(&input[1..], 3)?;
|
||||||
let (beta_bytes, envelope_bytes) = tokenize(data, 2)?;
|
let (beta_bytes, envelope_bytes) = tokenize(&data, 2)?;
|
||||||
|
|
||||||
let concatenated = [&beta_bytes[..], &envelope_bytes[..], &ke2m[..]].concat();
|
let concatenated = [&beta_bytes[..], &envelope_bytes[..], &ke2m[..]].concat();
|
||||||
Self::try_from(&concatenated[..])
|
Self::try_from(&concatenated[..])
|
||||||
@@ -494,8 +494,8 @@ pub struct ClientRegistration<CS: CipherSuite> {
|
|||||||
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientRegistration<CS> {
|
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientRegistration<CS> {
|
||||||
type Error = ProtocolError;
|
type Error = ProtocolError;
|
||||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let (id_u, bytes) = tokenize(input.to_vec(), 2)?;
|
let (id_u, bytes) = tokenize(&input, 2)?;
|
||||||
let (id_s, bytes) = tokenize(bytes.to_vec(), 2)?;
|
let (id_s, bytes) = tokenize(&bytes, 2)?;
|
||||||
|
|
||||||
let min_expected_len = <CS::Group as Group>::ScalarLen::to_usize();
|
let min_expected_len = <CS::Group as Group>::ScalarLen::to_usize();
|
||||||
let checked_slice = (if bytes.len() <= min_expected_len {
|
let checked_slice = (if bytes.len() <= min_expected_len {
|
||||||
@@ -931,8 +931,8 @@ pub struct ClientLogin<CS: CipherSuite> {
|
|||||||
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
|
||||||
type Error = ProtocolError;
|
type Error = ProtocolError;
|
||||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||||
let (id_u, bytes) = tokenize(input.to_vec(), 2)?;
|
let (id_u, bytes) = tokenize(&input, 2)?;
|
||||||
let (id_s, bytes) = tokenize(bytes.to_vec(), 2)?;
|
let (id_s, bytes) = tokenize(&bytes, 2)?;
|
||||||
|
|
||||||
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
|
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
|
||||||
let ke1_state_size =
|
let ke1_state_size =
|
||||||
@@ -1044,7 +1044,11 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
postprocess,
|
postprocess,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(alpha.to_arr().to_vec(), rng)?;
|
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(
|
||||||
|
alpha.to_arr().to_vec(),
|
||||||
|
Vec::new(), /* TODO set this */
|
||||||
|
rng,
|
||||||
|
)?;
|
||||||
|
|
||||||
let l1 = LoginFirstMessage { alpha, ke1_message };
|
let l1 = LoginFirstMessage { alpha, ke1_message };
|
||||||
|
|
||||||
@@ -1123,6 +1127,8 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
|||||||
<CS::KeyFormat as KeyPair>::Repr::from_bytes(
|
<CS::KeyFormat as KeyPair>::Repr::from_bytes(
|
||||||
&opened_envelope.credentials_map[&CredentialType::SkU],
|
&opened_envelope.credentials_map[&CredentialType::SkU],
|
||||||
)?,
|
)?,
|
||||||
|
Vec::new(), // TODO: fill in
|
||||||
|
Vec::new(), // TODO: fill in
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@@ -1218,6 +1224,8 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
|||||||
l1.ke1_message,
|
l1.ke1_message,
|
||||||
client_s_pk,
|
client_s_pk,
|
||||||
server_s_sk.clone(),
|
server_s_sk.clone(),
|
||||||
|
Vec::new(), // TODO populate this
|
||||||
|
Vec::new(), // TODO populate this
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let l2 = LoginSecondMessage {
|
let l2 = LoginSecondMessage {
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ pub(crate) fn serialize(input: &[u8], max_bytes: usize) -> Vec<u8> {
|
|||||||
|
|
||||||
// Tokenizes an input of the format I2OSP(len(input), max_bytes) || input, outputting
|
// Tokenizes an input of the format I2OSP(len(input), max_bytes) || input, outputting
|
||||||
// (input, remainder)
|
// (input, remainder)
|
||||||
pub(crate) fn tokenize(input: Vec<u8>, size_bytes: usize) -> Result<(Vec<u8>, Vec<u8>), PakeError> {
|
pub(crate) fn tokenize(input: &[u8], size_bytes: usize) -> Result<(Vec<u8>, Vec<u8>), PakeError> {
|
||||||
if size_bytes > std::mem::size_of::<usize>() || input.len() < size_bytes {
|
if size_bytes > std::mem::size_of::<usize>() || input.len() < size_bytes {
|
||||||
return Err(PakeError::SerializationError);
|
return Err(PakeError::SerializationError);
|
||||||
}
|
}
|
||||||
|
|||||||
+110
-3
@@ -34,6 +34,7 @@ impl CipherSuite for Default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MAX_ID_LENGTH: usize = 10;
|
const MAX_ID_LENGTH: usize = 10;
|
||||||
|
const MAX_INFO_LENGTH: usize = 10;
|
||||||
|
|
||||||
fn random_ristretto_point() -> RistrettoPoint {
|
fn random_ristretto_point() -> RistrettoPoint {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
@@ -195,7 +196,15 @@ fn login_first_message_roundtrip() {
|
|||||||
let mut client_nonce = [0u8; NONCE_LEN];
|
let mut client_nonce = [0u8; NONCE_LEN];
|
||||||
rng.fill_bytes(&mut client_nonce);
|
rng.fill_bytes(&mut client_nonce);
|
||||||
|
|
||||||
let ke1m: Vec<u8> = [&client_nonce[..], &client_e_kp.public()].concat();
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
|
||||||
|
let ke1m: Vec<u8> = [
|
||||||
|
&client_nonce[..],
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&client_e_kp.public(),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
let alpha_length = alpha_bytes.len();
|
let alpha_length = alpha_bytes.len();
|
||||||
let total_length_without_ke1m: usize = alpha_length + 2;
|
let total_length_without_ke1m: usize = alpha_length + 2;
|
||||||
@@ -238,7 +247,19 @@ fn login_second_message_roundtrip() {
|
|||||||
let mut server_nonce = [0u8; NONCE_LEN];
|
let mut server_nonce = [0u8; NONCE_LEN];
|
||||||
rng.fill_bytes(&mut server_nonce);
|
rng.fill_bytes(&mut server_nonce);
|
||||||
|
|
||||||
let ke2m: Vec<u8> = [&server_nonce[..], &server_e_kp.public(), &mac[..]].concat();
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut e_info);
|
||||||
|
|
||||||
|
let ke2m: Vec<u8> = [
|
||||||
|
&server_nonce[..],
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&server_e_kp.public(),
|
||||||
|
&serialize(&e_info.to_vec(), 2),
|
||||||
|
&mac[..],
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
let total_length_without_ke2m = pt_bytes.len() + envelope.to_bytes().len() + 2;
|
let total_length_without_ke2m = pt_bytes.len() + envelope.to_bytes().len() + 2;
|
||||||
|
|
||||||
@@ -257,6 +278,32 @@ fn login_second_message_roundtrip() {
|
|||||||
assert_eq!(input, l2_bytes);
|
assert_eq!(input, l2_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn login_third_message_roundtrip() {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut e_info);
|
||||||
|
let mut mac = [0u8; 32];
|
||||||
|
rng.fill_bytes(&mut mac);
|
||||||
|
|
||||||
|
let ke3m: Vec<u8> = [
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&serialize(&e_info.to_vec(), 2),
|
||||||
|
&mac[..],
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
|
let mut input = Vec::new();
|
||||||
|
input.extend_from_slice(&[ProtocolMessageType::KeyExchange as u8 + 1]);
|
||||||
|
input.extend_from_slice(&ke3m[..]);
|
||||||
|
|
||||||
|
let l3 = LoginThirdMessage::<Default>::deserialize(&input).unwrap();
|
||||||
|
let l3_bytes = l3.serialize();
|
||||||
|
assert_eq!(input, l3_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn client_login_roundtrip() {
|
fn client_login_roundtrip() {
|
||||||
let pw = b"hunter2";
|
let pw = b"hunter2";
|
||||||
@@ -303,13 +350,73 @@ fn ke1_message_roundtrip() {
|
|||||||
let mut client_nonce = [0u8; NONCE_LEN];
|
let mut client_nonce = [0u8; NONCE_LEN];
|
||||||
rng.fill_bytes(&mut client_nonce);
|
rng.fill_bytes(&mut client_nonce);
|
||||||
|
|
||||||
let ke1m: Vec<u8> = [&client_nonce[..], &client_e_kp.public()].concat();
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
|
||||||
|
let ke1m: Vec<u8> = [
|
||||||
|
&client_nonce[..],
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&client_e_kp.public(),
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
let reg =
|
let reg =
|
||||||
<TripleDH as KeyExchange<sha2::Sha256, crate::keypair::X25519KeyPair>>::KE1Message::try_from(&ke1m[..]).unwrap();
|
<TripleDH as KeyExchange<sha2::Sha256, crate::keypair::X25519KeyPair>>::KE1Message::try_from(&ke1m[..]).unwrap();
|
||||||
let reg_bytes = reg.to_bytes();
|
let reg_bytes = reg.to_bytes();
|
||||||
assert_eq!(reg_bytes, ke1m);
|
assert_eq!(reg_bytes, ke1m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ke2_message_roundtrip() {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
|
||||||
|
let server_e_kp = Default::generate_random_keypair(&mut rng).unwrap();
|
||||||
|
let mut mac = [0u8; 32];
|
||||||
|
rng.fill_bytes(&mut mac);
|
||||||
|
let mut server_nonce = [0u8; NONCE_LEN];
|
||||||
|
rng.fill_bytes(&mut server_nonce);
|
||||||
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut e_info);
|
||||||
|
|
||||||
|
let ke2m: Vec<u8> = [
|
||||||
|
&server_nonce[..],
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&server_e_kp.public(),
|
||||||
|
&serialize(&e_info.to_vec(), 2),
|
||||||
|
&mac[..],
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
|
let reg =
|
||||||
|
<TripleDH as KeyExchange<sha2::Sha256, crate::keypair::X25519KeyPair>>::KE2Message::try_from(&ke2m[..]).unwrap();
|
||||||
|
let reg_bytes = reg.to_bytes();
|
||||||
|
assert_eq!(reg_bytes, ke2m);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ke3_message_roundtrip() {
|
||||||
|
let mut rng = OsRng;
|
||||||
|
let mut info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut info);
|
||||||
|
let mut e_info = [0u8; MAX_INFO_LENGTH];
|
||||||
|
rng.fill_bytes(&mut e_info);
|
||||||
|
let mut mac = [0u8; 32];
|
||||||
|
rng.fill_bytes(&mut mac);
|
||||||
|
|
||||||
|
let ke3m: Vec<u8> = [
|
||||||
|
&serialize(&info.to_vec(), 2),
|
||||||
|
&serialize(&e_info.to_vec(), 2),
|
||||||
|
&mac[..],
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
|
let reg =
|
||||||
|
<TripleDH as KeyExchange<sha2::Sha256, crate::keypair::X25519KeyPair>>::KE3Message::try_from(&ke3m[..]).unwrap();
|
||||||
|
let reg_bytes = reg.to_bytes();
|
||||||
|
assert_eq!(reg_bytes, ke3m);
|
||||||
|
}
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+26
-26
@@ -66,35 +66,35 @@ pub struct TestVectorParameters {
|
|||||||
|
|
||||||
static TEST_VECTOR: &str = r#"
|
static TEST_VECTOR: &str = r#"
|
||||||
{
|
{
|
||||||
"client_s_pk": "bf958dfae87e144b9ef7e5599991ef5b3c057ce9bd0120d9812d56997ace575f",
|
"client_s_pk": "aee30cf198cc78b5b1a5ed5a4bda21bceb5e4732fffbddf867e32ee814d67317",
|
||||||
"client_s_sk": "d028843af0a5d410ee5a560ddda7e7c9c313f7793e54a41708a530e67de26677",
|
"client_s_sk": "1811b9d5fc4ea11b32405510632c643a2f760659c73298fe12a458ef39258b48",
|
||||||
"client_e_pk": "d3704416b573b0a3605a88971e144a1edcb5d981855fe54a77cdff02bf6e6457",
|
"client_e_pk": "1fb90ca40034a0ee0d9d087a2c12743329d792b21e4c4424e561a665a1031b00",
|
||||||
"client_e_sk": "7833dbb6853ff6ee3f9a69dad738c42de6cdf7c1ae7491248122b8169383ae4c",
|
"client_e_sk": "a86125633d89a6799a09456e45b5968e3958641c084e0e85185392ef67e59d40",
|
||||||
"server_s_pk": "c82312c965f9e08fda7aca33287beb2f1c39a0afbc6033ab22fa4ba3d4fb2d3f",
|
"server_s_pk": "9ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a57",
|
||||||
"server_s_sk": "3829629dc84a4a0fd3d04e225e108d2947668564326c3c45e80bc52c5fd8b16b",
|
"server_s_sk": "807548d5912d55092f88c5ba1ca2588a795b43adcdc877497d8a983a3c3ed146",
|
||||||
"server_e_pk": "415c2c4b1769268b1c7fc703cf652ce2df8249709d6d1b8b2608fff1e744e22b",
|
"server_e_pk": "b2df778b631c83d1fdd76feb9978d156ad0c1d18fedbe2b15a309f673e3d8464",
|
||||||
"server_e_sk": "a02800350e22a75a294d2365cb54f5c6ae6461514ce66b2d2b418965949b514d",
|
"server_e_sk": "f021332310d7f6a1c8272d11610e0244cf462efe1a7d9e6657cf12f74d30f272",
|
||||||
"id_u": "696455",
|
"id_u": "696455",
|
||||||
"id_s": "696453",
|
"id_s": "696453",
|
||||||
"password": "70617373776f7264",
|
"password": "70617373776f7264",
|
||||||
"blinding_factor": "5feb5851ccacfe610bef7bb970c05fb2f47381f6423fea4436248c6a77ac7a08",
|
"blinding_factor": "f614e957f0441399ede44bed38487eee12f154e5ac14adedb1402bdea174670b",
|
||||||
"oprf_key": "305500023999e82e0ac5f34c7d13dea3f88b9897cd91b6206f1df8ee2d856f0f",
|
"oprf_key": "9c13cf985a00394cb6acdebf846eafaa60d0ff81cd4d52655d6db3eee123760e",
|
||||||
"envelope_nonce": "c2d0720e9987bd4380068a6a23480bb1fa0eea01d84c71afb580f23fb09acae8",
|
"envelope_nonce": "b326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89",
|
||||||
"client_nonce": "ffaf9633c8dadc578524fa0993098fb0d30bb9ed092b0d5b2a75bf24381553c8",
|
"client_nonce": "8bdd8689f4ea9486aaa3bac182d31f31e3c62d76b3869ae1dd05d5c708b13e86",
|
||||||
"server_nonce": "441df2d948b11acbbe6e3ffcbc5fd6e2ff115176f5b16878d7c198371cff0927",
|
"server_nonce": "d529ed9480524236ed6f6cafd92ebab3c6091afde54f47f9079575c090cad7d6",
|
||||||
"r1": "010000220020b54de93fd9c9cadbfba797cba1e8a1469cbd673ed0fdfd2a6fda644d85664753",
|
"r1": "010000220020ada5910d73be53a8a6c50d32e9efcc0eb3e871103c05fb993fcb8312aff7fc79",
|
||||||
"r2": "020000280020a08e6edb2dfb4cc05c9c5530e7ef07532db317b959825546c49eed4a5b7c40a6000001010103",
|
"r2": "02000028002035104271fe25c0074ea715af805c019772a97b6e975376f411e1c37831a56fa7000001010103",
|
||||||
"r3": "030000aec2d0720e9987bd4380068a6a23480bb1fa0eea01d84c71afb580f23fb09acae80023306c65ae3f96ac0a892ea5843e0debe597cde1dbf2561c18c495839e2bc9e887fd10750023030020c82312c965f9e08fda7aca33287beb2f1c39a0afbc6033ab22fa4ba3d4fb2d3f0020251cd488033f5c5a7a85548e0b5c2424a7e0c331e11f51c6de67b697c3f9321c0020bf958dfae87e144b9ef7e5599991ef5b3c057ce9bd0120d9812d56997ace575f",
|
"r3": "030000aeb326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89002375ba1dad2970f60479c4ce0fe1e62271f2c5561757557c88941d9278ededbc981de07c00230300209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a570020c575cad080bafce229c0de9700269d48d8102d3f0f70497a770d9c0bcb5d181e0020aee30cf198cc78b5b1a5ed5a4bda21bceb5e4732fffbddf867e32ee814d67317",
|
||||||
"l1": "040000220020b54de93fd9c9cadbfba797cba1e8a1469cbd673ed0fdfd2a6fda644d85664753ffaf9633c8dadc578524fa0993098fb0d30bb9ed092b0d5b2a75bf24381553c8d3704416b573b0a3605a88971e144a1edcb5d981855fe54a77cdff02bf6e6457",
|
"l1": "040000220020ada5910d73be53a8a6c50d32e9efcc0eb3e871103c05fb993fcb8312aff7fc798bdd8689f4ea9486aaa3bac182d31f31e3c62d76b3869ae1dd05d5c708b13e8600001fb90ca40034a0ee0d9d087a2c12743329d792b21e4c4424e561a665a1031b00",
|
||||||
"l2": "050000ae0020a08e6edb2dfb4cc05c9c5530e7ef07532db317b959825546c49eed4a5b7c40a6c2d0720e9987bd4380068a6a23480bb1fa0eea01d84c71afb580f23fb09acae80023306c65ae3f96ac0a892ea5843e0debe597cde1dbf2561c18c495839e2bc9e887fd10750023030020c82312c965f9e08fda7aca33287beb2f1c39a0afbc6033ab22fa4ba3d4fb2d3f0020251cd488033f5c5a7a85548e0b5c2424a7e0c331e11f51c6de67b697c3f9321ca02800350e22a75a294d2365cb54f5c6ae6461514ce66b2d2b418965949b514d415c2c4b1769268b1c7fc703cf652ce2df8249709d6d1b8b2608fff1e744e22b79264b111c4ab164204f16d3f2da5a2cba3c736607f01906e60b3f70c887c1be",
|
"l2": "050000ae002035104271fe25c0074ea715af805c019772a97b6e975376f411e1c37831a56fa7b326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89002375ba1dad2970f60479c4ce0fe1e62271f2c5561757557c88941d9278ededbc981de07c00230300209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a570020c575cad080bafce229c0de9700269d48d8102d3f0f70497a770d9c0bcb5d181ef021332310d7f6a1c8272d11610e0244cf462efe1a7d9e6657cf12f74d30f2720000b2df778b631c83d1fdd76feb9978d156ad0c1d18fedbe2b15a309f673e3d846400003bc4221316aaad7b6110910bae5a3bc0e498738634916021546f6fce652adc78",
|
||||||
"l3": "ce39e86b59b96ae8497909a8b4a67f9cade11badbe7c95392a44ba9ca31362af",
|
"l3": "00000000a06be277ca4254db95ab90deeb5111effd46a9e619d26098806e34b8315f6c78",
|
||||||
"client_registration_state": "000369645500036964535feb5851ccacfe610bef7bb970c05fb2f47381f6423fea4436248c6a77ac7a0870617373776f7264",
|
"client_registration_state": "00036964550003696453f614e957f0441399ede44bed38487eee12f154e5ac14adedb1402bdea174670b70617373776f7264",
|
||||||
"client_login_state": "000369645500036964535feb5851ccacfe610bef7bb970c05fb2f47381f6423fea4436248c6a77ac7a087833dbb6853ff6ee3f9a69dad738c42de6cdf7c1ae7491248122b8169383ae4cffaf9633c8dadc578524fa0993098fb0d30bb9ed092b0d5b2a75bf24381553c812d4a730af1022f304f21cfe4cdcf98c0494da4c7c86f45e94b6449713990a9870617373776f7264",
|
"client_login_state": "00036964550003696453f614e957f0441399ede44bed38487eee12f154e5ac14adedb1402bdea174670ba86125633d89a6799a09456e45b5968e3958641c084e0e85185392ef67e59d408bdd8689f4ea9486aaa3bac182d31f31e3c62d76b3869ae1dd05d5c708b13e86b8990f815be25d3ab39421afac70cd6427ff73d364ed52d76320775e1320f7c570617373776f7264",
|
||||||
"server_registration_state": "305500023999e82e0ac5f34c7d13dea3f88b9897cd91b6206f1df8ee2d856f0f",
|
"server_registration_state": "9c13cf985a00394cb6acdebf846eafaa60d0ff81cd4d52655d6db3eee123760e",
|
||||||
"server_login_state": "c5b50039ee9c716d4bbbbae949322bdeaa23ab8e8b176832884b467f990ce55af2ee66df1a0b63ee7a3ae343231af7f2c64339238ec3cd0e261cc95727e47fd849bb17adafce3161fa1787d622f27bfeffa947d2bdd128c90e11c6aa4c04c390",
|
"server_login_state": "d71ab2471d28aec63b7c5227048a10e68e292b5acc75e12035816f3f1857740dcceb58e1095db8918dd41ad1aea631468dd161e165b5222d162f223dea33c53b50fc81d1199cf256ad4839860c168a5a42e785e4f375775ffd8f9f96c16d12ec",
|
||||||
"password_file": "305500023999e82e0ac5f34c7d13dea3f88b9897cd91b6206f1df8ee2d856f0fbf958dfae87e144b9ef7e5599991ef5b3c057ce9bd0120d9812d56997ace575fc2d0720e9987bd4380068a6a23480bb1fa0eea01d84c71afb580f23fb09acae80023306c65ae3f96ac0a892ea5843e0debe597cde1dbf2561c18c495839e2bc9e887fd10750023030020c82312c965f9e08fda7aca33287beb2f1c39a0afbc6033ab22fa4ba3d4fb2d3f0020251cd488033f5c5a7a85548e0b5c2424a7e0c331e11f51c6de67b697c3f9321c",
|
"password_file": "9c13cf985a00394cb6acdebf846eafaa60d0ff81cd4d52655d6db3eee123760eaee30cf198cc78b5b1a5ed5a4bda21bceb5e4732fffbddf867e32ee814d67317b326061dfc120f5b261b28bbae4262c26ad343a640b5fb4b90ba3f16600e1c89002375ba1dad2970f60479c4ce0fe1e62271f2c5561757557c88941d9278ededbc981de07c00230300209ef0646ad66cf13ce4052294c7325e044853f0c1fd03e91288f8339d812d4a570020c575cad080bafce229c0de9700269d48d8102d3f0f70497a770d9c0bcb5d181e",
|
||||||
"export_key": "2ae428e07164253279df1193a9904bb0b9419750142109818e594f537bd0b854",
|
"export_key": "405705c182c2afd6cc474cbd8827f4d046d74ec46b841727ae208333191be764",
|
||||||
"shared_secret": "49bb17adafce3161fa1787d622f27bfeffa947d2bdd128c90e11c6aa4c04c390"
|
"shared_secret": "50fc81d1199cf256ad4839860c168a5a42e785e4f375775ffd8f9f96c16d12ec"
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user