// Copyright (c) Meta Platforms, Inc. and affiliates. // // This source code is dual-licensed under either the MIT license found in the // LICENSE-MIT file in the root directory of this source tree or the Apache // License, Version 2.0 found in the LICENSE-APACHE file in the root directory // of this source tree. You may select, at your option, one of the above-listed // licenses. //! Contains the messages used for OPAQUE use core::ops::Add; use derive_where::derive_where; use digest::Output; use generic_array::sequence::Concat; use generic_array::typenum::{Sum, Unsigned}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen}; use zeroize::Zeroizing; use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash}; use crate::envelope::{Envelope, EnvelopeLen}; use crate::errors::ProtocolError; use crate::hash::OutputSize; use crate::key_exchange::group::Group; use crate::key_exchange::shared::NonceLen; use crate::key_exchange::traits::{ CredentialRequestParts, CredentialResponseParts, Deserialize, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, Serialize, }; use crate::keypair::PublicKey; use crate::opaque::{ MaskedResponse, MaskedResponseLen, ServerLogin, ServerLoginStartResult, ServerSetup, }; use crate::serialization::SliceExt; //////////////////////////// // High-level API Structs // // ====================== // //////////////////////////// /// The message sent by the client to the server, to initiate registration #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound = "") )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement)] pub struct RegistrationRequest { /// blinded password information pub(crate) blinded_element: voprf::BlindedElement, } /// The answer sent by the server to the user, upon reception of the /// registration attempt #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound = "") )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, as Group>::Pk)] pub struct RegistrationResponse { /// The server's oprf output pub(crate) evaluation_element: voprf::EvaluationElement, /// Server's static public key pub(crate) server_s_pk: PublicKey>, } /// The final message from the client, containing sealed cryptographic /// identifiers #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; as Group>::Pk)] 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: Output>, /// The user's public key pub(crate) client_s_pk: PublicKey>, } /// The message sent by the user to the server, to initiate registration #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( deserialize = "::KE1Message: serde::Deserialize<'de>", serialize = "::KE1Message: serde::Serialize" )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( Debug, Eq, Hash, PartialEq; voprf::BlindedElement, ::KE1Message, )] pub struct CredentialRequest { pub(crate) blinded_element: voprf::BlindedElement, pub(crate) ke1_message: ::KE1Message, } /// Builder for [`ServerLogin`](crate::ServerLogin) when using remote keys. #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( deserialize = "SK: serde::Deserialize<'de>, ::KE2Builder<'a, CS>: serde::Deserialize<'de>", serialize = "SK: serde::Serialize, ::KE2Builder<'a, CS>: \ serde::Serialize" )) )] #[derive_where(Clone)] #[derive_where( Debug, Eq, PartialEq; as Group>::Pk, SK, voprf::EvaluationElement, ::KE2Builder<'a, CS>, )] pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> { pub(crate) server_s_sk: SK, pub(crate) evaluation_element: voprf::EvaluationElement, pub(crate) masking_nonce: Zeroizing>, pub(crate) masked_response: MaskedResponse, #[cfg(test)] pub(crate) oprf_key: Zeroizing as voprf::Group>::ScalarLen>>, pub(crate) ke2_builder: ::KE2Builder<'a, CS>, } impl ServerLoginBuilder<'_, CS, SK> { /// The returned data here has to be processed and the result given as an /// input to [`ServerLoginBuilder::build()`]. To understand what kind of /// output is expected here and how to process it, refer to the /// documentation of your chosen [`CipherSuite::KeyExchange`]. pub fn data(&self) -> ::KE2BuilderData<'_, CS> { CS::KeyExchange::ke2_builder_data(&self.ke2_builder) } /// The handle to the corresponding [`ServerSetup`]s private key. pub fn private_key(&self) -> &SK { &self.server_s_sk } /// Build [`ServerLogin`] after attaining the input for the key exchange. To /// understand what kind of input is expected here, refer to the /// documentation of your chosen [`CipherSuite::KeyExchange`]. /// /// See [`ServerLogin::start()`] for the regular path. pub fn build( self, input: ::KE2BuilderInput, ) -> Result, ProtocolError> { ServerLogin::build(self, input) } } /// The answer sent by the server to the user, upon reception of the login /// attempt #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( deserialize = "::KE2Message: serde::Deserialize<'de>", serialize = "::KE2Message: serde::Serialize" )) )] #[derive_where(Clone)] #[derive_where( Debug, Eq, Hash, PartialEq; voprf::EvaluationElement, ::KE2Message, )] pub struct CredentialResponse { /// the server's oprf output pub(crate) evaluation_element: voprf::EvaluationElement, pub(crate) masking_nonce: GenericArray, pub(crate) masked_response: MaskedResponse, pub(crate) ke2_message: ::KE2Message, } /// The answer sent by the client to the server, upon reception of the sealed /// envelope #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( deserialize = "::KE3Message: serde::Deserialize<'de>", serialize = "::KE3Message: serde::Serialize" )) )] #[derive_where(Clone)] #[derive_where( Debug, Eq, Hash, PartialEq; ::KE3Message, )] pub struct CredentialFinalization { pub(crate) ke3_message: ::KE3Message, } //////////////////////////////// // High-level Implementations // // ========================== // //////////////////////////////// /// Length of [`RegistrationRequest`] in bytes for serialization. pub type RegistrationRequestLen = as voprf::Group>::ElemLen; impl RegistrationRequest { /// Only used for testing purposes #[cfg(test)] pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { self.blinded_element.clone() } /// Serialization into bytes pub fn serialize(&self) -> GenericArray> { as voprf::Group>::serialize_elem(self.blinded_element.value()) } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { Ok(Self { blinded_element: voprf::BlindedElement::deserialize(input)?, }) } } /// Length of [`RegistrationResponse`] in bytes for serialization. pub type RegistrationResponseLen = Sum< as voprf::Group>::ElemLen, as Group>::PkLen>; impl RegistrationResponse { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // RegistrationResponse: KgPk + KePk as voprf::Group>::ElemLen: Add< as Group>::PkLen>, RegistrationResponseLen: ArrayLength, { as voprf::Group>::serialize_elem(self.evaluation_element.value()) .concat(self.server_s_pk.serialize()) } /// Deserialization from bytes pub fn deserialize(mut input: &[u8]) -> Result { let evaluation_element = EvaluationElement::deserialize(input)?; input = &input[EvaluationElementLen::::USIZE..]; Ok(Self { evaluation_element, server_s_pk: PublicKey::deserialize_take(&mut input)?, }) } #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the /// reflection error case pub(crate) fn set_evaluation_element_for_testing( &self, beta: as voprf::Group>::Elem, ) -> Self { Self { evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), server_s_pk: self.server_s_pk.clone(), } } } /// Length of [`RegistrationUpload`] in bytes for serialization. pub type RegistrationUploadLen = Sum as Group>::PkLen, OutputSize>>, EnvelopeLen>; impl RegistrationUpload { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { self.client_s_pk .serialize() .concat(self.masking_key.clone()) .concat(self.envelope.serialize()) } /// Deserialization from bytes pub fn deserialize(mut input: &[u8]) -> Result { Ok(Self { client_s_pk: PublicKey::deserialize_take(&mut input)?, masking_key: input.take_array("masking key")?, envelope: Envelope::deserialize_take(&mut input)?, }) } // Creates a dummy instance used for faking a [CredentialResponse] pub(crate) fn dummy( rng: &mut R, server_setup: &ServerSetup, ) -> Self { let mut masking_key = Output::>::default(); rng.fill_bytes(&mut masking_key); Self { envelope: Envelope::::dummy(), masking_key, client_s_pk: server_setup.dummy_pk.clone(), } } } /// Length of [`CredentialRequest`] in bytes for serialization. pub type CredentialRequestLen = Sum< as voprf::Group>::ElemLen, Ke1MessageLen>; impl CredentialRequest { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where ::KE1Message: Serialize, // CredentialRequest: KgPk + Ke1Message as voprf::Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, { as voprf::Group>::serialize_elem(self.blinded_element.value()) .concat(self.ke1_message.serialize()) } /// Deserialization from bytes pub fn deserialize(mut input: &[u8]) -> Result where ::KE1Message: Deserialize, { Self::deserialize_take(&mut input) } pub(crate) fn deserialize_take(input: &mut &[u8]) -> Result where ::KE1Message: Deserialize, { let blinded_element = BlindedElement::deserialize(input)?; *input = &input[BlindedElementLen::::USIZE..]; Ok(Self { blinded_element, ke1_message: ::KE1Message::deserialize_take(input)?, }) } pub(crate) fn to_parts(&self) -> CredentialRequestParts { CredentialRequestParts::new(&self.blinded_element) } /// Only used for testing purposes #[cfg(test)] pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { self.blinded_element.clone() } } /// Length of [`CredentialResponse`] in bytes for serialization. pub type CredentialResponseLen = Sum, Ke2MessageLen>; pub(crate) type CredentialResponseWithoutKeLen = Sum as voprf::Group>::ElemLen, NonceLen>, MaskedResponseLen>; impl CredentialResponse { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where ::KE2Message: Serialize, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, CredentialResponseLen: ArrayLength, { as voprf::Group>::serialize_elem(self.evaluation_element.value()) .concat(self.masking_nonce) .concat(self.masked_response.serialize()) .concat(self.ke2_message.serialize()) } /// Deserialization from bytes pub fn deserialize(mut input: &[u8]) -> Result where ::KE2Message: Deserialize, { let evaluation_element = EvaluationElement::deserialize(input)?; input = &input[voprf::EvaluationElementLen::::USIZE..]; Ok(Self { evaluation_element, masking_nonce: input.take_array("masking nonce")?, masked_response: MaskedResponse::deserialize_take(&mut input)?, ke2_message: ::KE2Message::deserialize_take( &mut input, )?, }) } pub(crate) fn to_parts(&self) -> CredentialResponseParts { CredentialResponseParts::new( &self.evaluation_element, self.masking_nonce, self.masked_response.clone(), ) } #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the /// reflection error case pub(crate) fn set_evaluation_element_for_testing( &self, beta: as voprf::Group>::Elem, ) -> Self { Self { evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), masking_nonce: self.masking_nonce, masked_response: self.masked_response.clone(), ke2_message: self.ke2_message.clone(), } } } /// Length of [`CredentialFinalization`] in bytes for serialization. pub type CredentialFinalizationLen = Ke3MessageLen; impl CredentialFinalization { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where ::KE3Message: Serialize, { self.ke3_message.serialize() } /// Deserialization from bytes pub fn deserialize(mut input: &[u8]) -> Result where ::KE3Message: Deserialize, { Ok(Self { ke3_message: ::KE3Message::deserialize_take( &mut input, )?, }) } }