Updating AKE message format (#85)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
use crate::{
|
||||
errors::{InternalPakeError, ProtocolError},
|
||||
errors::{PakeError, ProtocolError},
|
||||
hash::Hash,
|
||||
keypair::KeyPair,
|
||||
};
|
||||
@@ -13,17 +13,19 @@ use rand_core::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
type KE1State: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
||||
type KE2State: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
||||
type KE1Message: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
||||
type KE2Message: for<'r> TryFrom<&'r [u8], Error = InternalPakeError> + ToBytes;
|
||||
type KE3Message: 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 = PakeError> + ToBytes;
|
||||
type KE1Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||
type KE2Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||
type KE3Message: for<'r> TryFrom<&'r [u8], Error = PakeError> + ToBytes;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
l1_component: Vec<u8>,
|
||||
info: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn generate_ke2<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
l1_bytes: Vec<u8>,
|
||||
@@ -31,6 +33,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
ke1_message: Self::KE1Message,
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
server_s_sk: KeyFormat::Repr,
|
||||
info: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError>;
|
||||
|
||||
fn generate_ke3(
|
||||
@@ -39,6 +43,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
ke1_state: &Self::KE1State,
|
||||
server_s_pk: KeyFormat::Repr,
|
||||
client_s_sk: KeyFormat::Repr,
|
||||
info: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError>;
|
||||
|
||||
fn finish_ke(
|
||||
|
||||
+121
-49
@@ -5,11 +5,14 @@
|
||||
|
||||
//! An implementation of the Triple Diffie-Hellman key exchange protocol
|
||||
use crate::{
|
||||
errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError},
|
||||
errors::{
|
||||
utils::{check_slice_size, check_slice_size_atleast},
|
||||
InternalPakeError, PakeError, ProtocolError,
|
||||
},
|
||||
hash::Hash,
|
||||
key_exchange::traits::{KeyExchange, ToBytes},
|
||||
keypair::{KeyPair, SizedBytesExt},
|
||||
serialization::serialize,
|
||||
serialization::{serialize, tokenize},
|
||||
};
|
||||
use digest::{Digest, FixedOutput};
|
||||
use generic_array::{
|
||||
@@ -47,6 +50,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
l1_component: Vec<u8>,
|
||||
info: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
|
||||
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 {
|
||||
client_nonce,
|
||||
info,
|
||||
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,
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
server_s_sk: KeyFormat::Repr,
|
||||
info: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
) -> Result<(Self::KE2State, Self::KE2Message), ProtocolError> {
|
||||
let server_e_kp = KeyFormat::generate_random(rng)?;
|
||||
let server_nonce: GenericArray<u8, NonceLen> = {
|
||||
@@ -102,8 +109,8 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
},
|
||||
&ke1_message.client_nonce,
|
||||
&server_nonce,
|
||||
client_s_pk,
|
||||
KeyFormat::public_from_private(&server_s_sk),
|
||||
&client_s_pk.to_arr(),
|
||||
&KeyFormat::public_from_private(&server_s_sk).to_arr(),
|
||||
)?;
|
||||
|
||||
let mut hasher = D::new();
|
||||
@@ -114,16 +121,25 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
&hashed_l1[..],
|
||||
&l2_bytes[..],
|
||||
&server_nonce[..],
|
||||
&serialize(&info, 2),
|
||||
&server_e_kp.public().to_arr(),
|
||||
&serialize(&e_info, 2),
|
||||
]
|
||||
.concat();
|
||||
|
||||
let mut hasher2 = D::new();
|
||||
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)?;
|
||||
mac.update(&hashed_transcript);
|
||||
let mut mac_hasher =
|
||||
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((
|
||||
KE2State {
|
||||
@@ -133,8 +149,10 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
},
|
||||
KE2Message {
|
||||
server_nonce,
|
||||
info,
|
||||
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,
|
||||
server_s_pk: KeyFormat::Repr,
|
||||
client_s_sk: KeyFormat::Repr,
|
||||
info: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Self::KE3Message), ProtocolError> {
|
||||
let (session_secret, km2, km3) = derive_3dh_keys::<KeyFormat, D>(
|
||||
TripleDHComponents {
|
||||
@@ -157,25 +177,24 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
},
|
||||
&ke1_state.client_nonce,
|
||||
&ke2_message.server_nonce,
|
||||
KeyFormat::public_from_private(&client_s_sk),
|
||||
server_s_pk,
|
||||
&KeyFormat::public_from_private(&client_s_sk).to_arr(),
|
||||
&server_s_pk.to_arr(),
|
||||
)?;
|
||||
|
||||
let transcript: Vec<u8> = [
|
||||
&ke1_state.hashed_l1[..],
|
||||
&l2_component[..],
|
||||
&ke2_message.server_nonce[..],
|
||||
&ke2_message.server_e_pk.to_arr(),
|
||||
&ke2_message.to_bytes_without_mac(),
|
||||
]
|
||||
.concat();
|
||||
|
||||
let mut hasher = D::new();
|
||||
hasher.update(&transcript);
|
||||
let hashed_transcript = hasher.finalize();
|
||||
let hashed_transcript_without_mac = hasher.finalize();
|
||||
|
||||
let mut server_mac =
|
||||
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() {
|
||||
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 =
|
||||
Hmac::<D>::new_varkey(&km3).map_err(|_| InternalPakeError::HmacError)?;
|
||||
client_mac.update(&hashed_transcript);
|
||||
client_mac.update(&transcript_with_ke3);
|
||||
|
||||
Ok((
|
||||
session_secret.to_vec(),
|
||||
KE3Message {
|
||||
info,
|
||||
e_info,
|
||||
mac: client_mac.finalize().into_bytes(),
|
||||
},
|
||||
))
|
||||
@@ -199,9 +232,14 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
ke3_message: Self::KE3Message,
|
||||
ke2_state: &Self::KE2State,
|
||||
) -> 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 =
|
||||
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() {
|
||||
return Err(ProtocolError::VerificationError(
|
||||
@@ -233,11 +271,12 @@ pub struct KE1State<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct KE1Message<KeyFormat: KeyPair> {
|
||||
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
||||
pub(crate) info: Vec<u8>,
|
||||
pub(crate) client_e_pk: KeyFormat::Repr,
|
||||
}
|
||||
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
type Error = InternalPakeError;
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_bytes =
|
||||
check_slice_size(ke1_message_bytes, NONCE_LEN + KEY_LEN, "ke1_message")?;
|
||||
let checked_nonce =
|
||||
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 {
|
||||
client_nonce: GenericArray::clone_from_slice(&checked_bytes[..NONCE_LEN]),
|
||||
client_e_pk: KeyFormat::Repr::from_bytes(&checked_bytes[NONCE_LEN..])?,
|
||||
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..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
|
||||
pub struct KE2Message<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
||||
server_nonce: GenericArray<u8, NonceLen>,
|
||||
info: Vec<u8>,
|
||||
server_e_pk: KeyFormat::Repr,
|
||||
e_info: Vec<u8>,
|
||||
mac: GenericArray<u8, HashLen>,
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE2State<HashLen> {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let output: Vec<u8> = [
|
||||
[
|
||||
&self.km3[..],
|
||||
&self.hashed_transcript[..],
|
||||
&self.session_secret[..],
|
||||
]
|
||||
.concat();
|
||||
output
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
let checked_bytes = check_slice_size(ke1_message_bytes, 3 * KEY_LEN, "ke2_state")?;
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_bytes = check_slice_size(input, 3 * KEY_LEN, "ke2_state")?;
|
||||
|
||||
Ok(Self {
|
||||
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> {
|
||||
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[..],
|
||||
&serialize(&self.info, 2),
|
||||
&self.server_e_pk.to_arr(),
|
||||
&self.mac[..],
|
||||
&serialize(&self.e_info, 2),
|
||||
]
|
||||
.concat();
|
||||
output
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
||||
for KE2Message<HashLen, KeyFormat>
|
||||
{
|
||||
type Error = InternalPakeError;
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(ke2_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let ke2_message_len = NONCE_LEN + KEY_LEN + HashLen::to_usize();
|
||||
let checked_bytes = check_slice_size(ke2_message_bytes, ke2_message_len, "ke2_message")?;
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_nonce = check_slice_size_atleast(input, NONCE_LEN, "ke2_message nonce")?;
|
||||
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 {
|
||||
server_nonce: GenericArray::clone_from_slice(&checked_bytes[..NONCE_LEN]),
|
||||
server_e_pk: KeyFormat::Repr::from_bytes(
|
||||
&checked_bytes[NONCE_LEN..NONCE_LEN + KEY_LEN],
|
||||
)?,
|
||||
mac: GenericArray::clone_from_slice(&checked_bytes[NONCE_LEN + KEY_LEN..]),
|
||||
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||
info,
|
||||
server_e_pk: KeyFormat::Repr::from_bytes(&checked_server_e_pk[..KEY_LEN])?,
|
||||
e_info,
|
||||
mac: GenericArray::clone_from_slice(&checked_mac),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -377,22 +437,34 @@ type TripleDHDerivationResult<D> = (
|
||||
|
||||
/// The third key exchange message
|
||||
pub struct KE3Message<HashLen: ArrayLength<u8>> {
|
||||
info: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
mac: GenericArray<u8, HashLen>,
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE3Message<HashLen> {
|
||||
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> {
|
||||
type Error = InternalPakeError;
|
||||
type Error = PakeError;
|
||||
|
||||
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 {
|
||||
info,
|
||||
e_info,
|
||||
mac: GenericArray::clone_from_slice(&checked_bytes),
|
||||
})
|
||||
}
|
||||
@@ -406,8 +478,8 @@ fn derive_3dh_keys<KeyFormat: KeyPair, D: Hash>(
|
||||
dh: TripleDHComponents<KeyFormat>,
|
||||
client_nonce: &GenericArray<u8, NonceLen>,
|
||||
server_nonce: &GenericArray<u8, NonceLen>,
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
server_s_pk: KeyFormat::Repr,
|
||||
id_u: &[u8],
|
||||
id_s: &[u8],
|
||||
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
|
||||
let ikm: Vec<u8> = [
|
||||
&KeyFormat::diffie_hellman(dh.pk1, dh.sk1)[..],
|
||||
@@ -420,8 +492,8 @@ fn derive_3dh_keys<KeyFormat: KeyPair, D: Hash>(
|
||||
STR_3DH,
|
||||
&serialize(&client_nonce, 2),
|
||||
&serialize(&server_nonce, 2),
|
||||
&serialize(&client_s_pk.to_arr(), 2),
|
||||
&serialize(&server_s_pk.to_arr(), 2),
|
||||
&serialize(id_u, 2),
|
||||
&serialize(id_s, 2),
|
||||
]
|
||||
.concat();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user