Adding client enumeration mitigations (#153)

This commit is contained in:
Kevin Lewi
2021-06-21 01:29:39 -07:00
committed by Kevin Lewi
parent 98f1821897
commit f0c13945d1
14 changed files with 895 additions and 901 deletions
+56 -39
View File
@@ -10,14 +10,16 @@ use crate::{
envelope::Envelope,
errors::{
utils::{check_slice_size, check_slice_size_atleast},
PakeError, ProtocolError,
ProtocolError, PakeError,
},
group::Group,
key_exchange::traits::{FromBytes, KeyExchange, ToBytes},
keypair::{KeyPair, PublicKey, SizedBytesExt},
};
use digest::Digest;
use generic_array::{typenum::Unsigned, GenericArray};
use generic_bytes::SizedBytes;
use rand::{CryptoRng, RngCore};
// Messages
// =========
@@ -127,6 +129,8 @@ pub struct RegistrationUpload<CS: CipherSuite> {
/// The "envelope" generated by the user, containing sealed
/// cryptographic identifiers
pub(crate) envelope: Envelope<CS::Hash>,
/// The masking key used to mask the envelope
pub(crate) masking_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
/// The user's public key
pub(crate) client_s_pk: PublicKey,
}
@@ -136,6 +140,7 @@ impl<CS: CipherSuite> Clone for RegistrationUpload<CS> {
fn clone(&self) -> Self {
Self {
envelope: self.envelope.clone(),
masking_key: self.masking_key.clone(),
client_s_pk: self.client_s_pk.clone(),
}
}
@@ -146,6 +151,7 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
pub fn serialize(&self) -> Vec<u8> {
[
self.client_s_pk.to_arr().to_vec(),
self.masking_key.to_vec(),
self.envelope.serialize(),
]
.concat()
@@ -154,22 +160,37 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let key_len = <PublicKey as SizedBytes>::Len::to_usize();
let checked_slice = check_slice_size_atleast(input, key_len, "registration_upload_bytes")?;
let (envelope, remainder) = Envelope::<CS::Hash>::deserialize(&checked_slice[key_len..])?;
if !remainder.is_empty() {
return Err(PakeError::SerializationError.into());
}
let hash_len = <CS::Hash as Digest>::OutputSize::to_usize();
let checked_slice = check_slice_size(
&input,
key_len + hash_len + Envelope::<CS::Hash>::len(),
"registration_upload_bytes",
)?;
let envelope = Envelope::<CS::Hash>::deserialize(&checked_slice[key_len + hash_len..])?;
Ok(Self {
envelope,
masking_key: GenericArray::clone_from_slice(
&checked_slice[key_len..key_len + hash_len],
),
client_s_pk: KeyPair::<CS::Group>::check_public_key(PublicKey::from_bytes(
&checked_slice[..key_len],
)?)?,
})
}
// Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut masking_key = vec![0u8; <CS::Hash as Digest>::OutputSize::to_usize()];
rng.fill_bytes(&mut masking_key);
let keypair = KeyPair::<CS::Group>::generate_random(rng);
Self {
envelope: Envelope::<CS::Hash>::dummy(),
masking_key: GenericArray::clone_from_slice(&masking_key),
client_s_pk: keypair.public().clone(),
}
}
}
impl_serialize_and_deserialize_for!(RegistrationUpload);
@@ -229,9 +250,8 @@ impl_serialize_and_deserialize_for!(CredentialRequest);
pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output
pub(crate) beta: CS::Group,
pub(crate) server_s_pk: PublicKey,
/// the user's sealed information,
pub(crate) envelope: Envelope<CS::Hash>,
pub(crate) masking_nonce: Vec<u8>,
pub(crate) masked_response: Vec<u8>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2Message,
}
@@ -240,8 +260,8 @@ impl<CS: CipherSuite> Clone for CredentialResponse<CS> {
fn clone(&self) -> Self {
Self {
beta: self.beta,
server_s_pk: self.server_s_pk.clone(),
envelope: self.envelope.clone(),
masking_nonce: self.masking_nonce.clone(),
masked_response: self.masked_response.clone(),
ke2_message: self.ke2_message.clone(),
}
}
@@ -251,7 +271,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
[
Self::serialize_without_ke(&self.beta, &self.server_s_pk, &self.envelope),
Self::serialize_without_ke(&self.beta, &self.masking_nonce, &self.masked_response),
self.ke2_message.to_bytes(),
]
.concat()
@@ -259,23 +279,26 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
pub(crate) fn serialize_without_ke(
beta: &CS::Group,
server_s_pk: &PublicKey,
envelope: &Envelope<CS::Hash>,
masking_nonce: &[u8],
masked_response: &[u8],
) -> Vec<u8> {
[
&beta.to_arr(),
&server_s_pk.to_arr()[..],
&envelope.to_bytes(),
]
.concat()
[&beta.to_arr(), masking_nonce, masked_response].concat()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize();
let key_len = <PublicKey as SizedBytes>::Len::to_usize();
let checked_slice =
check_slice_size_atleast(input, elem_len + key_len, "login_second_message_bytes")?;
let nonce_len: usize = 32;
let envelope_len = Envelope::<CS::Hash>::len();
let masked_response_len = key_len + envelope_len;
let ke2_message_len = CS::KeyExchange::ke2_message_size();
let checked_slice = check_slice_size_atleast(
input,
elem_len + nonce_len + masked_response_len + ke2_message_len,
"credential_response_bytes",
)?;
// Check that the message is actually containing an element of the
// correct subgroup
@@ -288,25 +311,19 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
return Err(PakeError::IdentityGroupElementError.into());
}
let unchecked_server_s_pk =
PublicKey::from_bytes(&checked_slice[elem_len..elem_len + key_len])?;
let server_s_pk = KeyPair::<CS::Group>::check_public_key(unchecked_server_s_pk)?;
let (envelope, remainder) =
Envelope::<CS::Hash>::deserialize(&checked_slice[elem_len + key_len..])?;
let ke2_message_size = CS::KeyExchange::ke2_message_size();
let checked_remainder =
check_slice_size_atleast(&remainder, ke2_message_size, "login_second_message_bytes")?;
let masking_nonce = checked_slice[elem_len..elem_len + nonce_len].to_vec();
let masked_response = checked_slice
[elem_len + nonce_len..elem_len + nonce_len + masked_response_len]
.to_vec();
let ke2_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2Message::from_bytes::<CS>(
checked_remainder,
&checked_slice[elem_len + nonce_len + masked_response_len..],
)?;
Ok(Self {
beta,
server_s_pk,
envelope,
masking_nonce,
masked_response,
ke2_message,
})
}