// Copyright (c) Facebook, Inc. and its affiliates. // // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. //! Contains the messages used for OPAQUE use crate::{ ciphersuite::CipherSuite, envelope::Envelope, errors::{ utils::{check_slice_size, check_slice_size_atleast}, 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 // ========= /// The message sent by the client to the server, to initiate registration pub struct RegistrationRequest { /// blinded password information pub(crate) alpha: CS::Group, } impl RegistrationRequest { /// Only used for testing purposes #[cfg(test)] pub fn get_alpha_for_testing(&self) -> CS::Group { self.alpha } } // Cannot be derived because it would require for CS to be Clone. impl Clone for RegistrationRequest { fn clone(&self) -> Self { Self { alpha: self.alpha } } } impl RegistrationRequest { /// Serialization into bytes pub fn serialize(&self) -> Vec { self.alpha.to_arr().to_vec() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let elem_len = ::ElemLen::to_usize(); let checked_slice = check_slice_size(input, elem_len, "first_message_bytes")?; // Check that the message is actually containing an element of the // correct subgroup let arr = GenericArray::from_slice(checked_slice); let alpha = CS::Group::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if alpha.is_identity() { return Err(PakeError::IdentityGroupElementError.into()); } Ok(Self { alpha }) } } impl_serialize_and_deserialize_for!(RegistrationRequest); /// The answer sent by the server to the user, upon reception of the /// registration attempt pub struct RegistrationResponse { /// The server's oprf output pub(crate) beta: CS::Group, /// Server's static public key pub(crate) server_s_pk: PublicKey, } // Cannot be derived because it would require for CS to be Clone. impl Clone for RegistrationResponse { fn clone(&self) -> Self { Self { beta: self.beta, server_s_pk: self.server_s_pk.clone(), } } } impl RegistrationResponse { /// Serialization into bytes pub fn serialize(&self) -> Vec { [self.beta.to_arr().to_vec(), self.server_s_pk.to_vec()].concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let elem_len = ::ElemLen::to_usize(); let key_len = ::Len::to_usize(); let checked_slice = check_slice_size(input, elem_len + key_len, "registration_response_bytes")?; // Check that the message is actually containing an element of the // correct subgroup let arr = GenericArray::from_slice(&checked_slice[..elem_len]); let beta = CS::Group::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if beta.is_identity() { return Err(PakeError::IdentityGroupElementError.into()); } // Ensure that public key is valid let server_s_pk = KeyPair::::check_public_key(PublicKey::from_bytes( &checked_slice[elem_len..], )?)?; Ok(Self { server_s_pk, beta }) } } impl_serialize_and_deserialize_for!(RegistrationResponse); /// The final message from the client, containing sealed cryptographic /// identifiers pub struct RegistrationUpload { /// The "envelope" generated by the user, containing sealed /// cryptographic identifiers pub(crate) envelope: Envelope, /// The masking key used to mask the envelope pub(crate) masking_key: GenericArray::OutputSize>, /// The user's public key pub(crate) client_s_pk: PublicKey, } // Cannot be derived because it would require for CS to be Clone. impl Clone for RegistrationUpload { fn clone(&self) -> Self { Self { envelope: self.envelope.clone(), masking_key: self.masking_key.clone(), client_s_pk: self.client_s_pk.clone(), } } } impl RegistrationUpload { /// Serialization into bytes pub fn serialize(&self) -> Vec { [ self.client_s_pk.to_arr().to_vec(), self.masking_key.to_vec(), self.envelope.serialize(), ] .concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let key_len = ::Len::to_usize(); let hash_len = ::OutputSize::to_usize(); let checked_slice = check_slice_size( &input, key_len + hash_len + Envelope::::len(), "registration_upload_bytes", )?; let envelope = Envelope::::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::::check_public_key(PublicKey::from_bytes( &checked_slice[..key_len], )?)?, }) } // Creates a dummy instance used for faking a [CredentialResponse] pub(crate) fn dummy(rng: &mut R) -> Self { let mut masking_key = vec![0u8; ::OutputSize::to_usize()]; rng.fill_bytes(&mut masking_key); let keypair = KeyPair::::generate_random(rng); Self { envelope: Envelope::::dummy(), masking_key: GenericArray::clone_from_slice(&masking_key), client_s_pk: keypair.public().clone(), } } } impl_serialize_and_deserialize_for!(RegistrationUpload); /// The message sent by the user to the server, to initiate registration pub struct CredentialRequest { /// blinded password information pub(crate) alpha: CS::Group, pub(crate) ke1_message: >::KE1Message, } // Cannot be derived because it would require for CS to be Clone. impl Clone for CredentialRequest { fn clone(&self) -> Self { Self { alpha: self.alpha, ke1_message: self.ke1_message.clone(), } } } impl CredentialRequest { /// Serialization into bytes pub fn serialize(&self) -> Vec { [self.alpha.to_arr().to_vec(), self.ke1_message.to_bytes()].concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let elem_len = ::ElemLen::to_usize(); let checked_slice = check_slice_size_atleast(input, elem_len, "login_first_message_bytes")?; // Check that the message is actually containing an element of the // correct subgroup let arr = GenericArray::from_slice(&checked_slice[..elem_len]); let alpha = CS::Group::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if alpha.is_identity() { return Err(PakeError::IdentityGroupElementError.into()); } let ke1_message = >::KE1Message::from_bytes::( &checked_slice[elem_len..], )?; Ok(Self { alpha, ke1_message }) } } impl_serialize_and_deserialize_for!(CredentialRequest); /// The answer sent by the server to the user, upon reception of the /// login attempt pub struct CredentialResponse { /// the server's oprf output pub(crate) beta: CS::Group, pub(crate) masking_nonce: Vec, pub(crate) masked_response: Vec, pub(crate) ke2_message: >::KE2Message, } // Cannot be derived because it would require for CS to be Clone. impl Clone for CredentialResponse { fn clone(&self) -> Self { Self { beta: self.beta, masking_nonce: self.masking_nonce.clone(), masked_response: self.masked_response.clone(), ke2_message: self.ke2_message.clone(), } } } impl CredentialResponse { /// Serialization into bytes pub fn serialize(&self) -> Vec { [ Self::serialize_without_ke(&self.beta, &self.masking_nonce, &self.masked_response), self.ke2_message.to_bytes(), ] .concat() } pub(crate) fn serialize_without_ke( beta: &CS::Group, masking_nonce: &[u8], masked_response: &[u8], ) -> Vec { [&beta.to_arr(), masking_nonce, masked_response].concat() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let elem_len = ::ElemLen::to_usize(); let key_len = ::Len::to_usize(); let nonce_len: usize = 32; let envelope_len = Envelope::::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 let beta_bytes = &checked_slice[..elem_len]; let arr = GenericArray::from_slice(beta_bytes); let beta = CS::Group::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if beta.is_identity() { return Err(PakeError::IdentityGroupElementError.into()); } 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 = >::KE2Message::from_bytes::( &checked_slice[elem_len + nonce_len + masked_response_len..], )?; Ok(Self { beta, masking_nonce, masked_response, ke2_message, }) } } impl_serialize_and_deserialize_for!(CredentialResponse); /// The answer sent by the client to the server, upon reception of the /// sealed envelope pub struct CredentialFinalization { pub(crate) ke3_message: >::KE3Message, } // Cannot be derived because it would require for CS to be Clone. impl Clone for CredentialFinalization { fn clone(&self) -> Self { Self { ke3_message: self.ke3_message.clone(), } } } impl CredentialFinalization { /// Serialization into bytes pub fn serialize(&self) -> Vec { self.ke3_message.to_bytes() } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let ke3_message = >::KE3Message::from_bytes::( input, )?; Ok(Self { ke3_message }) } } impl_serialize_and_deserialize_for!(CredentialFinalization);