Fixing test vectors and use of SHA512 (#120)

This commit is contained in:
Kevin Lewi
2021-01-26 09:27:30 -08:00
committed by GitHub
parent 6dc1c8b212
commit 6eeeb0db28
10 changed files with 708 additions and 290 deletions
-2
View File
@@ -56,8 +56,6 @@ pub trait KeyExchange<D: Hash, G: Group> {
ke2_state: &Self::KE2State,
) -> Result<Vec<u8>, ProtocolError>;
fn ke1_state_size() -> usize;
fn ke2_message_size() -> usize;
}
+20 -34
View File
@@ -44,14 +44,14 @@ static STR_OPAQUE: &[u8] = b"OPAQUE ";
pub struct TripleDH;
impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
type KE1State = KE1State<<D as FixedOutput>::OutputSize>;
type KE1State = KE1State;
type KE2State = KE2State<<D as FixedOutput>::OutputSize>;
type KE1Message = KE1Message;
type KE2Message = KE2Message<<D as FixedOutput>::OutputSize>;
type KE3Message = KE3Message<<D as FixedOutput>::OutputSize>;
fn generate_ke1<R: RngCore + CryptoRng>(
l1_component: Vec<u8>,
alpha_bytes: Vec<u8>,
info: Vec<u8>,
rng: &mut R,
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError> {
@@ -68,16 +68,14 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
client_e_pk: client_e_kp.public().clone(),
};
let l1_data: Vec<u8> = [&l1_component[..], &ke1_message.to_bytes()].concat();
let mut hasher = D::new();
hasher.update(&l1_data);
let hashed_l1 = hasher.finalize();
// TODO: must match the serialization of a credential request, could be done more cleanly
let serialized_credential_request = [alpha_bytes, ke1_message.to_bytes()].concat();
Ok((
KE1State {
client_e_sk: client_e_kp.private().clone(),
client_nonce,
hashed_l1,
serialized_credential_request,
},
ke1_message,
))
@@ -86,7 +84,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
#[allow(clippy::type_complexity)]
fn generate_ke2<R: RngCore + CryptoRng>(
rng: &mut R,
l1_bytes: Vec<u8>,
serialized_credential_request: Vec<u8>,
l2_bytes: Vec<u8>,
ke1_message: Self::KE1Message,
client_s_pk: Key,
@@ -118,7 +116,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
)?;
// Compute encryption of e_info
let h = Hkdf::<D>::new(None, &ke2);
let h = Hkdf::<D>::from_prk(&ke2).map_err(|_| InternalPakeError::HkdfError)?;
let mut encryption_pad = vec![0u8; e_info.len()];
h.expand(STR_ENCRYPTION_PAD, &mut encryption_pad)
.map_err(|_| InternalPakeError::HkdfError)?;
@@ -128,12 +126,8 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
.map(|(&x1, &x2)| x1 ^ x2)
.collect();
let mut hasher = D::new();
hasher.update(&l1_bytes);
let hashed_l1 = hasher.finalize();
let transcript2: Vec<u8> = [
&hashed_l1[..],
&serialized_credential_request[..],
&l2_bytes[..],
&server_nonce[..],
&server_e_kp.public().to_arr(),
@@ -152,7 +146,6 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
let mut hasher3 = D::new();
hasher3.update(&transcript2);
hasher3.update(mac.clone());
let hashed_transcript = hasher3.finalize();
Ok((
@@ -197,7 +190,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
)?;
let transcript: Vec<u8> = [
&ke1_state.hashed_l1[..],
&ke1_state.serialized_credential_request[..],
&l2_component[..],
&ke2_message.to_bytes_without_mac(),
]
@@ -219,7 +212,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
let mut hasher2 = D::new();
hasher2.update(transcript);
hasher2.update(ke2_message.mac.to_vec());
// hasher2.update(ke2_message.mac.to_vec()); // FIXME, sync with @caw on including this
let hashed_transcript = hasher2.finalize();
let mut client_mac =
@@ -227,7 +220,7 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
client_mac.update(&hashed_transcript);
// Compute decryption of e_info
let h = Hkdf::<D>::new(None, &ke2);
let h = Hkdf::<D>::from_prk(&ke2).map_err(|_| InternalPakeError::HkdfError)?;
let mut encryption_pad = vec![0u8; ke2_message.e_info.len()];
h.expand(STR_ENCRYPTION_PAD, &mut encryption_pad)
.map_err(|_| InternalPakeError::HkdfError)?;
@@ -264,10 +257,6 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
Ok(ke2_state.session_secret.to_vec())
}
fn ke1_state_size() -> usize {
NONCE_LEN + KEY_LEN + <<D as FixedOutput>::OutputSize as Unsigned>::to_usize()
}
fn ke2_message_size() -> usize {
NONCE_LEN + KEY_LEN + <<D as FixedOutput>::OutputSize as Unsigned>::to_usize()
}
@@ -275,10 +264,10 @@ impl<D: Hash, G: Group> KeyExchange<D, G> for TripleDH {
/// The client state produced after the first key exchange message
#[derive(PartialEq, Eq)]
pub struct KE1State<HashLen: ArrayLength<u8>> {
pub struct KE1State {
client_e_sk: Key,
client_nonce: GenericArray<u8, NonceLen>,
hashed_l1: GenericArray<u8, HashLen>,
serialized_credential_request: Vec<u8>,
}
/// The first key exchange message
@@ -289,32 +278,28 @@ pub struct KE1Message {
pub(crate) client_e_pk: Key,
}
impl<HashLen: ArrayLength<u8>> TryFrom<&[u8]> for KE1State<HashLen> {
impl TryFrom<&[u8]> for KE1State {
type Error = PakeError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let checked_bytes = check_slice_size(
bytes,
KEY_LEN + NONCE_LEN + HashLen::to_usize(),
"ke1_state",
)?;
let checked_bytes = check_slice_size_atleast(bytes, KEY_LEN + NONCE_LEN, "ke1_state")?;
Ok(Self {
client_e_sk: Key::from_bytes(&checked_bytes[..KEY_LEN])?,
client_nonce: GenericArray::clone_from_slice(
&checked_bytes[KEY_LEN..KEY_LEN + NONCE_LEN],
),
hashed_l1: GenericArray::clone_from_slice(&checked_bytes[KEY_LEN + NONCE_LEN..]),
serialized_credential_request: checked_bytes[KEY_LEN + NONCE_LEN..].to_vec(),
})
}
}
impl<HashLen: ArrayLength<u8>> ToBytes for KE1State<HashLen> {
impl ToBytes for KE1State {
fn to_bytes(&self) -> Vec<u8> {
let output: Vec<u8> = [
&self.client_e_sk.to_arr(),
&self.client_nonce[..],
&self.hashed_l1[..],
&self.serialized_credential_request[..],
]
.concat();
output
@@ -505,6 +490,7 @@ fn derive_3dh_keys<D: Hash, G: Group>(
let extracted_ikm = Hkdf::<D>::new(None, &ikm);
let handshake_secret = derive_secrets::<D>(&extracted_ikm, &STR_HANDSHAKE_SECRET, &info)?;
let session_secret = derive_secrets::<D>(&extracted_ikm, &STR_SESSION_SECRET, &info)?;
let km2 = hkdf_expand_label::<D>(
&handshake_secret,
&STR_SERVER_MAC,
@@ -538,7 +524,7 @@ fn hkdf_expand_label<D: Hash>(
context: &[u8],
length: usize,
) -> Result<Vec<u8>, ProtocolError> {
let h = Hkdf::<D>::new(None, secret);
let h = Hkdf::<D>::from_prk(secret).map_err(|_| InternalPakeError::HkdfError)?;
hkdf_expand_label_extracted(&h, label, context, length)
}