2020-11-16 14:05:43 -08:00
|
|
|
// Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
|
//
|
2021-12-03 14:38:11 -08:00
|
|
|
// This source code is licensed under both the MIT license found in the
|
|
|
|
|
// LICENSE-MIT file in the root directory of this source tree and the Apache
|
|
|
|
|
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
|
|
|
|
// of this source tree.
|
2020-11-16 14:05:43 -08:00
|
|
|
|
|
|
|
|
//! Contains the messages used for OPAQUE
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
ciphersuite::CipherSuite,
|
2022-01-04 00:50:40 +01:00
|
|
|
envelope::{Envelope, EnvelopeLen},
|
2020-11-16 14:05:43 -08:00
|
|
|
errors::{
|
|
|
|
|
utils::{check_slice_size, check_slice_size_atleast},
|
2021-08-22 12:28:19 -07:00
|
|
|
ProtocolError,
|
2020-11-16 14:05:43 -08:00
|
|
|
},
|
2021-10-25 02:54:32 -07:00
|
|
|
key_exchange::{
|
|
|
|
|
group::KeGroup,
|
2022-01-04 00:50:40 +01:00
|
|
|
traits::{FromBytes, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, ToBytes},
|
|
|
|
|
tripledh::NonceLen,
|
2021-10-25 02:54:32 -07:00
|
|
|
},
|
2021-08-17 05:11:53 +02:00
|
|
|
keypair::{KeyPair, PublicKey, SecretKey},
|
2022-01-04 00:50:40 +01:00
|
|
|
opaque::{MaskedResponse, MaskedResponseLen, ServerSetup},
|
|
|
|
|
};
|
|
|
|
|
use core::array::IntoIter;
|
|
|
|
|
use core::ops::Add;
|
|
|
|
|
use derive_where::DeriveWhere;
|
|
|
|
|
use digest::{Digest, FixedOutput};
|
|
|
|
|
use generic_array::sequence::Concat;
|
|
|
|
|
use generic_array::{
|
|
|
|
|
typenum::{Sum, Unsigned},
|
|
|
|
|
ArrayLength, GenericArray,
|
2020-11-16 14:05:43 -08:00
|
|
|
};
|
2021-04-16 01:07:07 -07:00
|
|
|
use rand::{CryptoRng, RngCore};
|
2021-10-25 02:54:32 -07:00
|
|
|
use voprf::group::Group;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
////////////////////////////
|
|
|
|
|
// High-level API Structs //
|
|
|
|
|
// ====================== //
|
|
|
|
|
////////////////////////////
|
2020-11-16 14:05:43 -08:00
|
|
|
|
|
|
|
|
/// The message sent by the client to the server, to initiate registration
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone)]
|
|
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; CS::OprfGroup)]
|
2021-02-17 02:13:03 -08:00
|
|
|
pub struct RegistrationRequest<CS: CipherSuite> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// blinded password information
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(RegistrationRequest);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
/// The answer sent by the server to the user, upon reception of the
|
|
|
|
|
/// registration attempt
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone)]
|
|
|
|
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; CS::OprfGroup)]
|
2021-09-25 16:36:00 -07:00
|
|
|
pub struct RegistrationResponse<CS: CipherSuite> {
|
|
|
|
|
/// The server's oprf output
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup, CS::Hash>,
|
2021-09-25 16:36:00 -07:00
|
|
|
/// Server's static public key
|
|
|
|
|
pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(
|
|
|
|
|
RegistrationResponse
|
|
|
|
|
where
|
|
|
|
|
// RegistrationResponse: KgPk + KePk
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
|
|
|
|
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
/// The final message from the client, containing sealed cryptographic
|
|
|
|
|
/// identifiers
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
2021-09-25 16:36:00 -07:00
|
|
|
pub struct RegistrationUpload<CS: CipherSuite> {
|
|
|
|
|
/// The "envelope" generated by the user, containing sealed
|
|
|
|
|
/// cryptographic identifiers
|
|
|
|
|
pub(crate) envelope: Envelope<CS>,
|
|
|
|
|
/// 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<CS::KeGroup>,
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(
|
|
|
|
|
RegistrationUpload
|
|
|
|
|
where
|
|
|
|
|
// Envelope: Nonce + Hash
|
|
|
|
|
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
|
|
|
|
<CS::KeGroup as KeGroup>::PkLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
Sum<<CS::KeGroup as KeGroup>::PkLen, <CS::Hash as FixedOutput>::OutputSize>:
|
|
|
|
|
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
|
|
|
|
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
/// The message sent by the user to the server, to initiate registration
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone, Zeroize)]
|
|
|
|
|
#[derive_where(
|
|
|
|
|
Debug, Eq, Hash, PartialEq;
|
|
|
|
|
CS::OprfGroup,
|
|
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
|
|
|
|
|
)]
|
2021-09-25 16:36:00 -07:00
|
|
|
pub struct CredentialRequest<CS: CipherSuite> {
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
|
2021-09-25 16:36:00 -07:00
|
|
|
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(
|
|
|
|
|
CredentialRequest
|
|
|
|
|
where
|
|
|
|
|
// CredentialRequest: KgPk + Ke1Message
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
|
|
|
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
/// The answer sent by the server to the user, upon reception of the
|
|
|
|
|
/// login attempt
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone)]
|
|
|
|
|
#[derive_where(
|
|
|
|
|
Debug, Eq, Hash, PartialEq;
|
|
|
|
|
CS::OprfGroup,
|
|
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
|
|
|
|
|
)]
|
2021-09-25 16:36:00 -07:00
|
|
|
pub struct CredentialResponse<CS: CipherSuite> {
|
|
|
|
|
/// the server's oprf output
|
2021-10-25 02:54:32 -07:00
|
|
|
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup, CS::Hash>,
|
2022-01-04 00:50:40 +01:00
|
|
|
pub(crate) masking_nonce: GenericArray<u8, NonceLen>,
|
|
|
|
|
pub(crate) masked_response: MaskedResponse<CS>,
|
2021-09-25 16:36:00 -07:00
|
|
|
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(
|
|
|
|
|
CredentialResponse
|
|
|
|
|
where
|
|
|
|
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
|
|
|
|
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
|
|
|
|
|
ArrayLength<u8> | Add<MaskedResponseLen<CS>>,
|
|
|
|
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// MaskedResponse: (Nonce + Hash) + KePk
|
|
|
|
|
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
Sum<NonceLen, <CS::Hash as FixedOutput>::OutputSize>:
|
|
|
|
|
ArrayLength<u8> | Add<<CS::KeGroup as KeGroup>::PkLen>,
|
|
|
|
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
|
|
|
|
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
|
|
|
|
CredentialResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
/// The answer sent by the client to the server, upon reception of the
|
|
|
|
|
/// sealed envelope
|
2022-01-04 00:50:40 +01:00
|
|
|
#[derive(DeriveWhere)]
|
|
|
|
|
#[derive_where(Clone)]
|
|
|
|
|
#[derive_where(
|
|
|
|
|
Debug, Eq, Hash, PartialEq;
|
|
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message,
|
|
|
|
|
)]
|
2021-09-25 16:36:00 -07:00
|
|
|
pub struct CredentialFinalization<CS: CipherSuite> {
|
|
|
|
|
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message,
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
impl_serialize_and_deserialize_for!(CredentialFinalization);
|
|
|
|
|
|
2021-09-25 16:36:00 -07:00
|
|
|
////////////////////////////////
|
|
|
|
|
// High-level Implementations //
|
|
|
|
|
// ========================== //
|
|
|
|
|
////////////////////////////////
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`RegistrationRequest`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type RegistrationRequestLen<CS: CipherSuite> = <CS::OprfGroup as Group>::ElemLen;
|
|
|
|
|
|
2021-06-15 17:31:12 -07:00
|
|
|
impl<CS: CipherSuite> RegistrationRequest<CS> {
|
|
|
|
|
/// Only used for testing purposes
|
|
|
|
|
#[cfg(test)]
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn get_blinded_element_for_testing(
|
|
|
|
|
&self,
|
|
|
|
|
) -> voprf::BlindedElement<CS::OprfGroup, CS::Hash> {
|
|
|
|
|
self.blinded_element.clone()
|
2021-06-15 17:31:12 -07:00
|
|
|
}
|
2021-06-22 15:48:36 +02:00
|
|
|
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, RegistrationRequestLen<CS>> {
|
|
|
|
|
self.blinded_element.value().to_arr()
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-10-25 02:54:32 -07:00
|
|
|
Ok(Self {
|
|
|
|
|
blinded_element: voprf::BlindedElement::deserialize(input)?,
|
|
|
|
|
})
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`RegistrationResponse`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type RegistrationResponseLen<CS: CipherSuite> =
|
|
|
|
|
Sum<<CS::OprfGroup as Group>::ElemLen, <CS::KeGroup as KeGroup>::PkLen>;
|
|
|
|
|
|
2021-02-17 02:13:03 -08:00
|
|
|
impl<CS: CipherSuite> RegistrationResponse<CS> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
|
|
|
|
|
where
|
|
|
|
|
// RegistrationResponse: KgPk + KePk
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
|
|
|
|
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
{
|
|
|
|
|
self.evaluation_element
|
|
|
|
|
.value()
|
|
|
|
|
.to_arr()
|
|
|
|
|
.concat(self.server_s_pk.to_arr())
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-08-17 05:11:53 +02:00
|
|
|
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
|
2021-10-25 02:54:32 -07:00
|
|
|
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
2021-02-20 03:51:04 -08:00
|
|
|
let checked_slice =
|
2021-06-12 23:18:08 -07:00
|
|
|
check_slice_size(input, elem_len + key_len, "registration_response_bytes")?;
|
2021-01-26 09:27:30 -08:00
|
|
|
|
2021-06-15 17:31:12 -07:00
|
|
|
// Ensure that public key is valid
|
2021-08-04 21:24:46 +02:00
|
|
|
let server_s_pk = KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
|
2021-06-15 10:48:29 +02:00
|
|
|
&checked_slice[elem_len..],
|
|
|
|
|
)?)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
Ok(Self {
|
|
|
|
|
evaluation_element: voprf::EvaluationElement::deserialize(&checked_slice[..elem_len])?,
|
|
|
|
|
server_s_pk,
|
|
|
|
|
})
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
2021-07-12 12:33:19 -07:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
/// Only used for tests, where we can set the beta value to test for the reflection
|
|
|
|
|
/// error case
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn set_evaluation_element_for_testing(&self, beta: CS::OprfGroup) -> Self {
|
2021-07-12 12:33:19 -07:00
|
|
|
Self {
|
2021-10-25 02:54:32 -07:00
|
|
|
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
2021-07-12 12:33:19 -07:00
|
|
|
server_s_pk: self.server_s_pk.clone(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`RegistrationUpload`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type RegistrationUploadLen<CS: CipherSuite> = Sum<
|
|
|
|
|
Sum<<CS::KeGroup as KeGroup>::PkLen, <CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
EnvelopeLen<CS>,
|
|
|
|
|
>;
|
|
|
|
|
|
2021-02-17 02:13:03 -08:00
|
|
|
impl<CS: CipherSuite> RegistrationUpload<CS> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, RegistrationUploadLen<CS>>
|
|
|
|
|
where
|
|
|
|
|
// Envelope: Nonce + Hash
|
|
|
|
|
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
|
|
|
|
<CS::KeGroup as KeGroup>::PkLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
Sum<<CS::KeGroup as KeGroup>::PkLen, <CS::Hash as FixedOutput>::OutputSize>:
|
|
|
|
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
|
|
|
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
|
|
|
|
{
|
|
|
|
|
self.client_s_pk
|
|
|
|
|
.to_arr()
|
|
|
|
|
.concat(self.masking_key.clone())
|
|
|
|
|
.concat(self.envelope.serialize())
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-10-25 02:54:32 -07:00
|
|
|
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
2021-08-17 05:11:53 +02:00
|
|
|
let hash_len = <CS::Hash as Digest>::OutputSize::USIZE;
|
2021-04-30 15:56:51 -07:00
|
|
|
let checked_slice =
|
|
|
|
|
check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?;
|
|
|
|
|
let envelope = Envelope::<CS>::deserialize(&checked_slice[key_len + hash_len..])?;
|
2020-11-16 14:05:43 -08:00
|
|
|
Ok(Self {
|
|
|
|
|
envelope,
|
2021-04-16 01:07:07 -07:00
|
|
|
masking_key: GenericArray::clone_from_slice(
|
|
|
|
|
&checked_slice[key_len..key_len + hash_len],
|
|
|
|
|
),
|
2021-08-04 21:24:46 +02:00
|
|
|
client_s_pk: KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
|
2021-02-20 03:51:04 -08:00
|
|
|
&checked_slice[..key_len],
|
|
|
|
|
)?)?,
|
2020-11-16 14:05:43 -08:00
|
|
|
})
|
|
|
|
|
}
|
2021-04-16 01:07:07 -07:00
|
|
|
|
|
|
|
|
// Creates a dummy instance used for faking a [CredentialResponse]
|
2021-08-04 21:24:46 +02:00
|
|
|
pub(crate) fn dummy<R: RngCore + CryptoRng, S: SecretKey<CS::KeGroup>>(
|
2021-04-30 15:56:51 -07:00
|
|
|
rng: &mut R,
|
2021-07-20 11:49:37 +02:00
|
|
|
server_setup: &ServerSetup<CS, S>,
|
2021-04-30 15:56:51 -07:00
|
|
|
) -> Self {
|
2022-01-04 00:50:40 +01:00
|
|
|
let mut masking_key = GenericArray::<_, <CS::Hash as Digest>::OutputSize>::default();
|
2021-04-16 01:07:07 -07:00
|
|
|
rng.fill_bytes(&mut masking_key);
|
|
|
|
|
|
|
|
|
|
Self {
|
2021-04-30 15:56:51 -07:00
|
|
|
envelope: Envelope::<CS>::dummy(),
|
2022-01-04 00:50:40 +01:00
|
|
|
masking_key,
|
2021-04-30 15:56:51 -07:00
|
|
|
client_s_pk: server_setup.fake_keypair.public().clone(),
|
2021-04-16 01:07:07 -07:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`CredentialRequest`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type CredentialRequestLen<CS: CipherSuite> =
|
|
|
|
|
Sum<<CS::OprfGroup as Group>::ElemLen, Ke1MessageLen<CS>>;
|
|
|
|
|
|
2020-12-12 21:53:33 -08:00
|
|
|
impl<CS: CipherSuite> CredentialRequest<CS> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, CredentialRequestLen<CS>>
|
|
|
|
|
where
|
|
|
|
|
// CredentialRequest: KgPk + Ke1Message
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
|
|
|
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
|
|
|
|
{
|
|
|
|
|
self.blinded_element
|
|
|
|
|
.value()
|
|
|
|
|
.to_arr()
|
|
|
|
|
.concat(self.ke1_message.to_bytes())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn serialize_iter<'a>(
|
|
|
|
|
blinded_element: &'a GenericArray<u8, <CS::OprfGroup as Group>::ElemLen>,
|
|
|
|
|
ke1_message: &'a GenericArray<u8, Ke1MessageLen<CS>>,
|
|
|
|
|
) -> impl Iterator<Item = &'a [u8]> {
|
|
|
|
|
// MSRV: array `into_iter` isn't available in 1.51
|
|
|
|
|
#[allow(deprecated)]
|
|
|
|
|
IntoIter::new([blinded_element.as_slice(), ke1_message])
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-08-17 05:11:53 +02:00
|
|
|
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
|
2021-01-26 09:27:30 -08:00
|
|
|
|
2021-06-12 23:18:08 -07:00
|
|
|
let checked_slice = check_slice_size_atleast(input, elem_len, "login_first_message_bytes")?;
|
2021-01-26 09:27:30 -08:00
|
|
|
|
|
|
|
|
// Check that the message is actually containing an element of the
|
|
|
|
|
// correct subgroup
|
2021-10-25 02:54:32 -07:00
|
|
|
let blinded_element = voprf::BlindedElement::<CS::OprfGroup, CS::Hash>::deserialize(
|
|
|
|
|
&checked_slice[..elem_len],
|
|
|
|
|
)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
2021-06-15 17:31:12 -07:00
|
|
|
// Throw an error if the identity group element is encountered
|
2021-10-25 02:54:32 -07:00
|
|
|
if blinded_element.value().is_identity() {
|
2021-08-22 12:28:19 -07:00
|
|
|
return Err(ProtocolError::IdentityGroupElementError);
|
2021-06-15 17:31:12 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-16 14:05:43 -08:00
|
|
|
let ke1_message =
|
2022-01-04 00:50:40 +01:00
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes(
|
2021-01-26 09:27:30 -08:00
|
|
|
&checked_slice[elem_len..],
|
|
|
|
|
)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
2021-10-25 02:54:32 -07:00
|
|
|
Ok(Self {
|
|
|
|
|
blinded_element,
|
|
|
|
|
ke1_message,
|
|
|
|
|
})
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
2021-07-12 12:33:19 -07:00
|
|
|
|
|
|
|
|
/// Only used for testing purposes
|
|
|
|
|
#[cfg(test)]
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn get_blinded_element_for_testing(
|
|
|
|
|
&self,
|
|
|
|
|
) -> voprf::BlindedElement<CS::OprfGroup, CS::Hash> {
|
|
|
|
|
self.blinded_element.clone()
|
2021-07-12 12:33:19 -07:00
|
|
|
}
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`CredentialResponse`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type CredentialResponseLen<CS: CipherSuite> =
|
|
|
|
|
Sum<CredentialResponseWithoutKeLen<CS>, Ke2MessageLen<CS>>;
|
|
|
|
|
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub(crate) type CredentialResponseWithoutKeLen<CS: CipherSuite> =
|
|
|
|
|
Sum<Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>, MaskedResponseLen<CS>>;
|
|
|
|
|
|
2020-12-12 21:53:33 -08:00
|
|
|
impl<CS: CipherSuite> CredentialResponse<CS> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, CredentialResponseLen<CS>>
|
|
|
|
|
where
|
|
|
|
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
|
|
|
|
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
|
|
|
|
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
|
|
|
|
|
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
|
|
|
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// MaskedResponse: (Nonce + Hash) + KePk
|
|
|
|
|
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
|
|
|
|
|
Sum<NonceLen, <CS::Hash as FixedOutput>::OutputSize>:
|
|
|
|
|
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
|
|
|
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
|
|
|
|
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
|
|
|
|
CredentialResponseLen<CS>: ArrayLength<u8>,
|
|
|
|
|
{
|
|
|
|
|
self.evaluation_element
|
|
|
|
|
.value()
|
|
|
|
|
.to_arr()
|
|
|
|
|
.concat(self.masking_nonce)
|
|
|
|
|
.concat(self.masked_response.serialize())
|
|
|
|
|
.concat(self.ke2_message.to_bytes())
|
2021-02-02 12:12:20 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
pub(crate) fn serialize_without_ke<'a>(
|
|
|
|
|
beta: &'a GenericArray<u8, <CS::OprfGroup as Group>::ElemLen>,
|
|
|
|
|
masking_nonce: &'a GenericArray<u8, NonceLen>,
|
|
|
|
|
masked_response: &'a MaskedResponse<CS>,
|
|
|
|
|
) -> impl Iterator<Item = &'a [u8]> {
|
|
|
|
|
// MSRV: array `into_iter` isn't available in 1.51
|
|
|
|
|
#[allow(deprecated)]
|
|
|
|
|
IntoIter::new([beta.as_slice(), masking_nonce.as_slice()])
|
|
|
|
|
.into_iter()
|
|
|
|
|
.chain(masked_response.iter())
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-08-17 05:11:53 +02:00
|
|
|
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
|
2021-10-25 02:54:32 -07:00
|
|
|
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
2021-04-16 01:07:07 -07:00
|
|
|
let nonce_len: usize = 32;
|
2021-04-30 15:56:51 -07:00
|
|
|
let envelope_len = Envelope::<CS>::len();
|
2021-04-16 01:07:07 -07:00
|
|
|
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",
|
|
|
|
|
)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
|
|
|
|
// Check that the message is actually containing an element of the
|
|
|
|
|
// correct subgroup
|
|
|
|
|
let beta_bytes = &checked_slice[..elem_len];
|
2021-10-25 02:54:32 -07:00
|
|
|
let evaluation_element =
|
|
|
|
|
voprf::EvaluationElement::<CS::OprfGroup, CS::Hash>::deserialize(beta_bytes)?;
|
2020-11-16 14:05:43 -08:00
|
|
|
|
2021-06-15 17:31:12 -07:00
|
|
|
// Throw an error if the identity group element is encountered
|
2021-10-25 02:54:32 -07:00
|
|
|
if evaluation_element.value().is_identity() {
|
2021-08-22 12:28:19 -07:00
|
|
|
return Err(ProtocolError::IdentityGroupElementError);
|
2021-06-15 17:31:12 -07:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
let masking_nonce =
|
|
|
|
|
GenericArray::clone_from_slice(&checked_slice[elem_len..elem_len + nonce_len]);
|
|
|
|
|
let masked_response = MaskedResponse::deserialize(
|
|
|
|
|
&checked_slice[elem_len + nonce_len..elem_len + nonce_len + masked_response_len],
|
|
|
|
|
);
|
2020-11-16 14:05:43 -08:00
|
|
|
let ke2_message =
|
2022-01-04 00:50:40 +01:00
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message::from_bytes(
|
2021-04-16 01:07:07 -07:00
|
|
|
&checked_slice[elem_len + nonce_len + masked_response_len..],
|
2020-11-16 14:05:43 -08:00
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
Ok(Self {
|
2021-10-25 02:54:32 -07:00
|
|
|
evaluation_element,
|
2021-04-16 01:07:07 -07:00
|
|
|
masking_nonce,
|
|
|
|
|
masked_response,
|
2020-11-16 14:05:43 -08:00
|
|
|
ke2_message,
|
|
|
|
|
})
|
|
|
|
|
}
|
2021-07-12 12:33:19 -07:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
/// Only used for tests, where we can set the beta value to test for the reflection
|
|
|
|
|
/// error case
|
2021-10-25 02:54:32 -07:00
|
|
|
pub fn set_evaluation_element_for_testing(&self, beta: CS::OprfGroup) -> Self {
|
2021-07-12 12:33:19 -07:00
|
|
|
Self {
|
2021-10-25 02:54:32 -07:00
|
|
|
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
2022-01-04 00:50:40 +01:00
|
|
|
masking_nonce: self.masking_nonce,
|
2021-07-12 12:33:19 -07:00
|
|
|
masked_response: self.masked_response.clone(),
|
|
|
|
|
ke2_message: self.ke2_message.clone(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
2022-01-04 00:50:40 +01:00
|
|
|
/// Length of [`CredentialFinalization`] in bytes for serialization.
|
|
|
|
|
#[allow(type_alias_bounds)]
|
|
|
|
|
pub type CredentialFinalizationLen<CS: CipherSuite> = Ke3MessageLen<CS>;
|
|
|
|
|
|
2020-12-12 21:53:33 -08:00
|
|
|
impl<CS: CipherSuite> CredentialFinalization<CS> {
|
2020-11-16 14:05:43 -08:00
|
|
|
/// Serialization into bytes
|
2022-01-04 00:50:40 +01:00
|
|
|
pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>> {
|
|
|
|
|
self.ke3_message.to_bytes()
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Deserialization from bytes
|
|
|
|
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
2021-02-17 02:47:00 -08:00
|
|
|
let ke3_message =
|
2022-01-04 00:50:40 +01:00
|
|
|
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message::from_bytes(input)?;
|
2021-02-17 02:47:00 -08:00
|
|
|
Ok(Self { ke3_message })
|
2020-11-16 14:05:43 -08:00
|
|
|
}
|
|
|
|
|
}
|