Turning KeyPair into a struct (#119)
This commit is contained in:
@@ -5,14 +5,15 @@
|
||||
|
||||
use crate::{
|
||||
errors::{PakeError, ProtocolError},
|
||||
group::Group,
|
||||
hash::Hash,
|
||||
keypair::KeyPair,
|
||||
keypair::Key,
|
||||
};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
pub trait KeyExchange<D: Hash, G: Group> {
|
||||
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;
|
||||
@@ -31,8 +32,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
l1_bytes: Vec<u8>,
|
||||
l2_bytes: Vec<u8>,
|
||||
ke1_message: Self::KE1Message,
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
server_s_sk: KeyFormat::Repr,
|
||||
client_s_pk: Key,
|
||||
server_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
id_s: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
@@ -43,8 +44,8 @@ pub trait KeyExchange<D: Hash, KeyFormat: KeyPair> {
|
||||
l2_component: Vec<u8>,
|
||||
ke2_message: Self::KE2Message,
|
||||
ke1_state: &Self::KE1State,
|
||||
server_s_pk: KeyFormat::Repr,
|
||||
client_s_sk: KeyFormat::Repr,
|
||||
server_s_pk: Key,
|
||||
client_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
id_s: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError>;
|
||||
|
||||
@@ -9,9 +9,10 @@ use crate::{
|
||||
utils::{check_slice_size, check_slice_size_atleast},
|
||||
InternalPakeError, PakeError, ProtocolError,
|
||||
},
|
||||
group::Group,
|
||||
hash::Hash,
|
||||
key_exchange::traits::{KeyExchange, ToBytes},
|
||||
keypair::{KeyPair, SizedBytesExt},
|
||||
keypair::{Key, KeyPair, SizedBytesExt},
|
||||
serialization::{serialize, tokenize},
|
||||
};
|
||||
use digest::{Digest, FixedOutput};
|
||||
@@ -29,7 +30,6 @@ use std::convert::TryFrom;
|
||||
const KEY_LEN: usize = 32;
|
||||
pub(crate) const NONCE_LEN: usize = 32;
|
||||
pub(crate) type NonceLen = U32;
|
||||
const KE1_STATE_LEN: usize = KEY_LEN + KEY_LEN + NONCE_LEN;
|
||||
|
||||
static STR_3DH: &[u8] = b"3DH keys";
|
||||
static STR_CLIENT_MAC: &[u8] = b"client mac";
|
||||
@@ -43,11 +43,11 @@ static STR_OPAQUE: &[u8] = b"OPAQUE ";
|
||||
/// The Triple Diffie-Hellman key exchange implementation
|
||||
pub struct TripleDH;
|
||||
|
||||
impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
type KE1State = KE1State<<D as FixedOutput>::OutputSize, KeyFormat>;
|
||||
impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
|
||||
type KE1State = KE1State<<D as FixedOutput>::OutputSize>;
|
||||
type KE2State = KE2State<<D as FixedOutput>::OutputSize>;
|
||||
type KE1Message = KE1Message<KeyFormat>;
|
||||
type KE2Message = KE2Message<<D as FixedOutput>::OutputSize, KeyFormat>;
|
||||
type KE1Message = KE1Message;
|
||||
type KE2Message = KE2Message<<D as FixedOutput>::OutputSize>;
|
||||
type KE3Message = KE3Message<<D as FixedOutput>::OutputSize>;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
@@ -55,7 +55,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
info: Vec<u8>,
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
|
||||
let client_e_kp = KeyFormat::generate_random(rng)?;
|
||||
let client_e_kp = KeyPair::<G>::generate_random(rng);
|
||||
let client_nonce: GenericArray<u8, NonceLen> = {
|
||||
let mut client_nonce_bytes = [0u8; NONCE_LEN];
|
||||
rng.fill_bytes(&mut client_nonce_bytes);
|
||||
@@ -89,20 +89,20 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
l1_bytes: Vec<u8>,
|
||||
l2_bytes: Vec<u8>,
|
||||
ke1_message: Self::KE1Message,
|
||||
client_s_pk: KeyFormat::Repr,
|
||||
server_s_sk: KeyFormat::Repr,
|
||||
client_s_pk: Key,
|
||||
server_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
id_s: Vec<u8>,
|
||||
e_info: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Self::KE2State, Self::KE2Message), ProtocolError> {
|
||||
let server_e_kp = KeyFormat::generate_random(rng)?;
|
||||
let server_e_kp = KeyPair::<G>::generate_random(rng);
|
||||
let server_nonce: GenericArray<u8, NonceLen> = {
|
||||
let mut server_nonce_bytes = [0u8; NONCE_LEN];
|
||||
rng.fill_bytes(&mut server_nonce_bytes);
|
||||
server_nonce_bytes.into()
|
||||
};
|
||||
|
||||
let (session_secret, km2, ke2, km3) = derive_3dh_keys::<KeyFormat, D>(
|
||||
let (session_secret, km2, ke2, km3) = derive_3dh_keys::<D, G>(
|
||||
TripleDHComponents {
|
||||
pk1: ke1_message.client_e_pk.clone(),
|
||||
sk1: server_e_kp.private().clone(),
|
||||
@@ -176,12 +176,12 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
l2_component: Vec<u8>,
|
||||
ke2_message: Self::KE2Message,
|
||||
ke1_state: &Self::KE1State,
|
||||
server_s_pk: KeyFormat::Repr,
|
||||
client_s_sk: KeyFormat::Repr,
|
||||
server_s_pk: Key,
|
||||
client_s_sk: Key,
|
||||
id_u: Vec<u8>,
|
||||
id_s: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>, Self::KE3Message), ProtocolError> {
|
||||
let (session_secret, km2, ke2, km3) = derive_3dh_keys::<KeyFormat, D>(
|
||||
let (session_secret, km2, ke2, km3) = derive_3dh_keys::<D, G>(
|
||||
TripleDHComponents {
|
||||
pk1: ke2_message.server_e_pk.clone(),
|
||||
sk1: ke1_state.client_e_sk.clone(),
|
||||
@@ -265,7 +265,7 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
}
|
||||
|
||||
fn ke1_state_size() -> usize {
|
||||
KE1_STATE_LEN
|
||||
NONCE_LEN + KEY_LEN + <<D as FixedOutput>::OutputSize as Unsigned>::to_usize()
|
||||
}
|
||||
|
||||
fn ke2_message_size() -> usize {
|
||||
@@ -275,21 +275,21 @@ impl<D: Hash, KeyFormat: KeyPair> KeyExchange<D, KeyFormat> for TripleDH {
|
||||
|
||||
/// The client state produced after the first key exchange message
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct KE1State<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
||||
client_e_sk: KeyFormat::Repr,
|
||||
pub struct KE1State<HashLen: ArrayLength<u8>> {
|
||||
client_e_sk: Key,
|
||||
client_nonce: GenericArray<u8, NonceLen>,
|
||||
hashed_l1: GenericArray<u8, HashLen>,
|
||||
}
|
||||
|
||||
/// The first key exchange message
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct KE1Message<KeyFormat: KeyPair> {
|
||||
pub struct KE1Message {
|
||||
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
||||
pub(crate) info: Vec<u8>,
|
||||
pub(crate) client_e_pk: KeyFormat::Repr,
|
||||
pub(crate) client_e_pk: Key,
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]> for KE1State<HashLen, KeyFormat> {
|
||||
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE1State<HashLen> {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
@@ -300,7 +300,7 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]> for KE1State<H
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
client_e_sk: KeyFormat::Repr::from_bytes(&checked_bytes[..KEY_LEN])?,
|
||||
client_e_sk: Key::from_bytes(&checked_bytes[..KEY_LEN])?,
|
||||
client_nonce: GenericArray::clone_from_slice(
|
||||
&checked_bytes[KEY_LEN..KEY_LEN + NONCE_LEN],
|
||||
),
|
||||
@@ -309,7 +309,7 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]> for KE1State<H
|
||||
}
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE1State<HashLen, KeyFormat> {
|
||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE1State<HashLen> {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
let output: Vec<u8> = [
|
||||
&self.client_e_sk.to_arr(),
|
||||
@@ -321,7 +321,7 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE1State<HashLen,
|
||||
}
|
||||
}
|
||||
|
||||
impl<KeyFormat: KeyPair> ToBytes for KE1Message<KeyFormat> {
|
||||
impl ToBytes for KE1Message {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
[
|
||||
&self.client_nonce[..],
|
||||
@@ -332,7 +332,7 @@ impl<KeyFormat: KeyPair> ToBytes for KE1Message<KeyFormat> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<KeyFormat: KeyPair> TryFrom<&[u8]> for KE1Message<KeyFormat> {
|
||||
impl TryFrom<&[u8]> for KE1Message {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(ke1_message_bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
@@ -346,7 +346,7 @@ impl<KeyFormat: KeyPair> TryFrom<&[u8]> for KE1Message<KeyFormat> {
|
||||
Ok(Self {
|
||||
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||
info,
|
||||
client_e_pk: KeyFormat::Repr::from_bytes(&checked_client_e_pk)?,
|
||||
client_e_pk: Key::from_bytes(&checked_client_e_pk)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -358,9 +358,9 @@ pub struct KE2State<HashLen: ArrayLength<u8>> {
|
||||
}
|
||||
|
||||
/// The second key exchange message
|
||||
pub struct KE2Message<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> {
|
||||
pub struct KE2Message<HashLen: ArrayLength<u8>> {
|
||||
server_nonce: GenericArray<u8, NonceLen>,
|
||||
server_e_pk: KeyFormat::Repr,
|
||||
server_e_pk: Key,
|
||||
e_info: Vec<u8>,
|
||||
mac: GenericArray<u8, HashLen>,
|
||||
}
|
||||
@@ -380,23 +380,28 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2State<HashLen> {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_bytes = check_slice_size(input, 3 * KEY_LEN, "ke2_state")?;
|
||||
let hash_len = HashLen::to_usize();
|
||||
let checked_bytes = check_slice_size(input, 3 * hash_len, "ke2_state")?;
|
||||
|
||||
Ok(Self {
|
||||
km3: GenericArray::clone_from_slice(&checked_bytes[..KEY_LEN]),
|
||||
hashed_transcript: GenericArray::clone_from_slice(&checked_bytes[KEY_LEN..2 * KEY_LEN]),
|
||||
session_secret: GenericArray::clone_from_slice(&checked_bytes[2 * KEY_LEN..]),
|
||||
km3: GenericArray::clone_from_slice(&checked_bytes[..hash_len]),
|
||||
hashed_transcript: GenericArray::clone_from_slice(
|
||||
&checked_bytes[hash_len..2 * hash_len],
|
||||
),
|
||||
session_secret: GenericArray::clone_from_slice(
|
||||
&checked_bytes[2 * hash_len..3 * hash_len],
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> ToBytes for KE2Message<HashLen, KeyFormat> {
|
||||
impl<HashLen: ArrayLength<u8>> ToBytes for KE2Message<HashLen> {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
[&self.to_bytes_without_mac(), &self.mac[..]].concat()
|
||||
}
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> KE2Message<HashLen, KeyFormat> {
|
||||
impl<HashLen: ArrayLength<u8>> KE2Message<HashLen> {
|
||||
fn to_bytes_without_mac(&self) -> Vec<u8> {
|
||||
[
|
||||
&self.server_nonce[..],
|
||||
@@ -407,9 +412,7 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> KE2Message<HashLen, KeyFormat
|
||||
}
|
||||
}
|
||||
|
||||
impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
||||
for KE2Message<HashLen, KeyFormat>
|
||||
{
|
||||
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE2Message<HashLen> {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
@@ -424,7 +427,7 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
||||
|
||||
Ok(Self {
|
||||
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..NONCE_LEN]),
|
||||
server_e_pk: KeyFormat::Repr::from_bytes(&checked_server_e_pk[..KEY_LEN])?,
|
||||
server_e_pk: Key::from_bytes(&checked_server_e_pk[..KEY_LEN])?,
|
||||
e_info,
|
||||
mac: GenericArray::clone_from_slice(&checked_mac),
|
||||
})
|
||||
@@ -432,13 +435,13 @@ impl<HashLen: ArrayLength<u8>, KeyFormat: KeyPair> TryFrom<&[u8]>
|
||||
}
|
||||
|
||||
// The triple of public and private components used in the 3DH computation
|
||||
struct TripleDHComponents<KeyFormat: KeyPair> {
|
||||
pk1: KeyFormat::Repr,
|
||||
sk1: KeyFormat::Repr,
|
||||
pk2: KeyFormat::Repr,
|
||||
sk2: KeyFormat::Repr,
|
||||
pk3: KeyFormat::Repr,
|
||||
sk3: KeyFormat::Repr,
|
||||
struct TripleDHComponents {
|
||||
pk1: Key,
|
||||
sk1: Key,
|
||||
pk2: Key,
|
||||
sk2: Key,
|
||||
pk3: Key,
|
||||
sk3: Key,
|
||||
}
|
||||
|
||||
// Consists of a shared secret, followed by two mac keys and an encryption key: (session_secret, km2, ke2, km3)
|
||||
@@ -464,7 +467,7 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE3Message<HashLen> {
|
||||
type Error = PakeError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||
let checked_bytes = check_slice_size(&bytes, KEY_LEN, "ke3_message")?;
|
||||
let checked_bytes = check_slice_size(&bytes, HashLen::to_usize(), "ke3_message")?;
|
||||
|
||||
Ok(Self {
|
||||
mac: GenericArray::clone_from_slice(&checked_bytes),
|
||||
@@ -476,17 +479,17 @@ impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE3Message<HashLen> {
|
||||
|
||||
// Internal function which takes the public and private components of the client and server keypairs, along
|
||||
// with some auxiliary metadata, to produce the shared secret and two MAC keys
|
||||
fn derive_3dh_keys<KeyFormat: KeyPair, D: Hash>(
|
||||
dh: TripleDHComponents<KeyFormat>,
|
||||
fn derive_3dh_keys<D: Hash, G: Group>(
|
||||
dh: TripleDHComponents,
|
||||
client_nonce: &GenericArray<u8, NonceLen>,
|
||||
server_nonce: &GenericArray<u8, NonceLen>,
|
||||
id_u: &[u8],
|
||||
id_s: &[u8],
|
||||
) -> Result<TripleDHDerivationResult<D>, ProtocolError> {
|
||||
let ikm: Vec<u8> = [
|
||||
&KeyFormat::diffie_hellman(dh.pk1, dh.sk1)[..],
|
||||
&KeyFormat::diffie_hellman(dh.pk2, dh.sk2)[..],
|
||||
&KeyFormat::diffie_hellman(dh.pk3, dh.sk3)[..],
|
||||
&KeyPair::<G>::diffie_hellman(dh.pk1, dh.sk1)?[..],
|
||||
&KeyPair::<G>::diffie_hellman(dh.pk2, dh.sk2)?[..],
|
||||
&KeyPair::<G>::diffie_hellman(dh.pk3, dh.sk3)?[..],
|
||||
]
|
||||
.concat();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user