Voprf update (#255)

* Update to latest voprf

* Upgrade to Rust edition 2021

* Fix Clippy

* Remove all allocations

* Remove unnecessary `allow(type_alias_bounds)`

* Make all serialization infallible

* Remove self-dependency

* Update rustyline
This commit is contained in:
daxpedda
2022-01-05 15:10:57 -08:00
committed by GitHub
parent 82e4436d39
commit 36f0a55518
26 changed files with 1399 additions and 876 deletions
+290 -145
View File
@@ -11,34 +11,33 @@ use crate::{
ciphersuite::CipherSuite,
envelope::{Envelope, EnvelopeLen},
errors::{utils::check_slice_size, InternalError, ProtocolError},
hash::Hash,
hash::{Hash, OutputSize, ProxyHash},
key_exchange::{
group::KeGroup,
traits::{FromBytes, Ke1MessageLen, Ke2StateLen, KeyExchange, ToBytes},
traits::{FromBytes, Ke1MessageLen, Ke1StateLen, Ke2StateLen, KeyExchange, ToBytes},
tripledh::NonceLen,
},
keypair::{KeyPair, PrivateKey, PublicKey, SecretKey},
messages::{CredentialRequestLen, RegistrationUploadLen},
serialization::{tokenize, Serialize},
serialization::Serialize,
slow_hash::SlowHash,
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload,
};
use alloc::vec::Vec;
use core::array::IntoIter;
use core::marker::PhantomData;
use core::ops::Add;
use derive_where::DeriveWhere;
use digest::{Digest, FixedOutput};
use digest::core_api::{BlockSizeUser, CoreProxy};
use digest::Output;
use generic_array::sequence::Concat;
use generic_array::{
typenum::{Sum, Unsigned, U2},
typenum::{IsLess, Le, NonZero, Sum, Unsigned, U2, U256},
ArrayLength, GenericArray,
};
use hkdf::{Hkdf, HkdfExtract};
use rand::{CryptoRng, RngCore};
use subtle::ConstantTimeEq;
use voprf::group::Group;
use voprf::Group;
///////////////
// Constants //
@@ -73,8 +72,12 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
pub struct ServerSetup<
CS: CipherSuite,
S: SecretKey<CS::KeGroup> = PrivateKey<<CS as CipherSuite>::KeGroup>,
> {
oprf_seed: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
> where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
oprf_seed: Output<CS::Hash>,
keypair: KeyPair<CS::KeGroup, S>,
pub(crate) fake_keypair: KeyPair<CS::KeGroup>,
}
@@ -87,27 +90,42 @@ pub struct ServerSetup<
voprf::NonVerifiableClient<CS::OprfGroup, CS::Hash>,
voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
)]
pub struct ClientRegistration<CS: CipherSuite> {
pub struct ClientRegistration<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) oprf_client: voprf::NonVerifiableClient<CS::OprfGroup, CS::Hash>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
}
impl_serialize_and_deserialize_for!(ClientRegistration; serde_::ser::Error::custom);
impl_serialize_and_deserialize_for!(
ClientRegistration
where
// ClientRegistration: KgSk + KgPk
<CS::OprfGroup as Group>::ScalarLen: Add<<CS::OprfGroup as Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
);
/// The state elements the server holds to record a registration
#[derive(DeriveWhere)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
pub struct ServerRegistration<CS: CipherSuite>(RegistrationUpload<CS>);
pub struct ServerRegistration<CS: CipherSuite>(RegistrationUpload<CS>)
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl_serialize_and_deserialize_for!(
ServerRegistration
where
// Envelope: Nonce + Hash
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
NonceLen: Add<OutputSize<CS::Hash>>,
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>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
@@ -122,7 +140,12 @@ impl_serialize_and_deserialize_for!(
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State,
CredentialRequest<CS>,
)]
pub struct ClientLogin<CS: CipherSuite> {
pub struct ClientLogin<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
oprf_client: voprf::NonVerifiableClient<CS::OprfGroup, CS::Hash>,
ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State,
credential_request: CredentialRequest<CS>,
@@ -133,8 +156,12 @@ impl_serialize_and_deserialize_for!(
where
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>;
serde_::ser::Error::custom
CredentialRequestLen<CS>: ArrayLength<u8>,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<CS::OprfGroup as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
Sum<<CS::OprfGroup as Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> | Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
);
/// The state elements the server holds to record a login
@@ -144,7 +171,12 @@ impl_serialize_and_deserialize_for!(
Debug, Eq, Hash, PartialEq;
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State,
)]
pub struct ServerLogin<CS: CipherSuite> {
pub struct ServerLogin<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State,
#[derive_where(skip(Zeroize))]
_cs: PhantomData<CS>,
@@ -160,7 +192,12 @@ impl_serialize_and_deserialize_for!(ServerLogin);
// Server Setup
// ============
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::KeGroup>> {
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::KeGroup>>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Generate a new instance of server setup
pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
let keypair = KeyPair::generate_random(rng);
@@ -169,11 +206,15 @@ impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::KeGroup>> {
}
/// Length of [`ServerSetup`] in bytes for serialization.
#[allow(type_alias_bounds)]
pub type ServerSetupLen<CS: CipherSuite, S: SecretKey<CS::KeGroup>> =
Sum<Sum<<CS::Hash as FixedOutput>::OutputSize, S::Len>, <CS::KeGroup as KeGroup>::SkLen>;
Sum<Sum<OutputSize<CS::Hash>, S::Len>, <CS::KeGroup as KeGroup>::SkLen>;
impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S> {
impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Create [`ServerSetup`] with the given keypair
pub fn new_with_key<R: CryptoRng + RngCore>(
rng: &mut R,
@@ -193,9 +234,8 @@ impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S> {
pub fn serialize(&self) -> GenericArray<u8, ServerSetupLen<CS, S>>
where
// ServerSetup: Hash + KeSk + KeSk
<CS::Hash as FixedOutput>::OutputSize: Add<S::Len>,
Sum<<CS::Hash as FixedOutput>::OutputSize, S::Len>:
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::SkLen>,
OutputSize<CS::Hash>: Add<S::Len>,
Sum<OutputSize<CS::Hash>, S::Len>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::SkLen>,
ServerSetupLen<CS, S>: ArrayLength<u8>,
{
self.oprf_seed
@@ -206,7 +246,7 @@ impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S> {
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> {
let seed_len = <CS::Hash as Digest>::OutputSize::USIZE;
let seed_len = OutputSize::<CS::Hash>::USIZE;
let key_len = <CS::KeGroup as KeGroup>::SkLen::USIZE;
let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")?;
@@ -227,39 +267,46 @@ impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S> {
// Registration
// ============
impl<CS: CipherSuite> ClientRegistration<CS> {
pub(crate) type ClientRegistrationLen<CS: CipherSuite> =
Sum<<CS::OprfGroup as Group>::ScalarLen, <CS::OprfGroup as Group>::ElemLen>;
impl<CS: CipherSuite> ClientRegistration<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> Result<Vec<u8>, ProtocolError> {
Ok(chain!(
Serialize::<U2>::from(&self.oprf_client.serialize())?.iter(),
Serialize::<U2>::from(&self.blinded_element.serialize())?.iter(),
)
.flatten()
.cloned()
.collect())
pub fn serialize(&self) -> GenericArray<u8, ClientRegistrationLen<CS>>
where
// ClientRegistration: KgSk + KgPk
<CS::OprfGroup as Group>::ScalarLen: Add<<CS::OprfGroup as Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
{
self.oprf_client
.serialize()
.concat(self.blinded_element.serialize())
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let (serialized_oprf_client, remainder) = tokenize(input, 2)?;
let (serialized_blinded_element, remainder) = tokenize(remainder, 2)?;
if !remainder.is_empty() {
return Err(ProtocolError::SerializationError);
}
let client_len = <CS::OprfGroup as Group>::ScalarLen::USIZE;
let element_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
let checked_slice =
check_slice_size(input, client_len + element_len, "client_registration")?;
Ok(Self {
oprf_client: voprf::NonVerifiableClient::deserialize(serialized_oprf_client)?,
blinded_element: voprf::BlindedElement::deserialize(serialized_blinded_element)?,
oprf_client: voprf::NonVerifiableClient::deserialize(&checked_slice[..client_len])?,
blinded_element: voprf::BlindedElement::deserialize(&checked_slice[client_len..])?,
})
}
/// Only used for testing zeroize
#[cfg(test)]
pub(crate) fn to_vec(&self) -> Vec<u8> {
pub(crate) fn to_vec(&self) -> std::vec::Vec<u8> {
[
self.oprf_client.serialize(),
self.blinded_element.serialize(),
self.oprf_client.serialize().to_vec(),
self.blinded_element.serialize().to_vec(),
]
.concat()
}
@@ -287,6 +334,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
pub fn finish<R: CryptoRng + RngCore>(
self,
rng: &mut R,
password: &[u8],
registration_response: RegistrationResponse<CS>,
params: ClientRegistrationFinishParameters<CS>,
) -> Result<ClientRegistrationFinishResult<CS>, ProtocolError> {
@@ -302,12 +350,13 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
#[cfg_attr(not(test), allow(unused_variables))]
let (randomized_pwd, randomized_pwd_hasher) = get_password_derived_key::<CS>(
password,
self.oprf_client.clone(),
registration_response.evaluation_element,
params.slow_hash,
)?;
let mut masking_key = GenericArray::<_, <CS::Hash as Digest>::OutputSize>::default();
let mut masking_key = Output::<CS::Hash>::default();
randomized_pwd_hasher
.expand(STR_MASKING_KEY, &mut masking_key)
.map_err(|_| InternalError::HkdfError)?;
@@ -340,16 +389,21 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// Length of [`ServerRegistration`] in bytes for serialization.
pub type ServerRegistrationLen<CS> = RegistrationUploadLen<CS>;
impl<CS: CipherSuite> ServerRegistration<CS> {
impl<CS: CipherSuite> ServerRegistration<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, ServerRegistrationLen<CS>>
where
// Envelope: Nonce + Hash
NonceLen: Add<<CS::Hash as FixedOutput>::OutputSize>,
NonceLen: Add<OutputSize<CS::Hash>>,
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>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
@@ -375,7 +429,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
)?;
let server = voprf::NonVerifiableServer::new_with_key(&oprf_key)?;
let evaluate_result = server.evaluate(message.blinded_element, None)?;
let evaluate_result = server.evaluate(&message.blinded_element, None)?;
Ok(ServerRegistrationStartResult {
message: RegistrationResponse {
@@ -405,55 +459,64 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
// Login
// =====
impl<CS: CipherSuite> ClientLogin<CS> {
pub(crate) type ClientLoginLen<CS: CipherSuite> =
Sum<Sum<<CS::OprfGroup as Group>::ScalarLen, CredentialRequestLen<CS>>, Ke1StateLen<CS>>;
impl<CS: CipherSuite> ClientLogin<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> Result<Vec<u8>, ProtocolError>
pub fn serialize(&self) -> GenericArray<u8, ClientLoginLen<CS>>
where
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<CS::OprfGroup as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
Sum<<CS::OprfGroup as Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
{
Ok(chain!(
Serialize::<U2>::from(&self.oprf_client.serialize())?.iter(),
Serialize::<U2>::from(&self.credential_request.serialize())?.iter(),
Serialize::<U2>::from(&self.ke1_state.to_bytes())?.iter(),
)
.flatten()
.cloned()
.collect())
self.oprf_client
.serialize()
.concat(self.credential_request.serialize())
.concat(self.ke1_state.to_bytes())
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let (serialized_oprf_client, remainder) = tokenize(input, 2)?;
let (serialized_credential_request, remainder) = tokenize(remainder, 2)?;
let (ke1_state_bytes, remainder) = tokenize(remainder, 2)?;
if !remainder.is_empty() {
return Err(ProtocolError::SerializationError);
}
let client_len = <CS::OprfGroup as Group>::ScalarLen::USIZE;
let request_len = <CS::OprfGroup as Group>::ElemLen::USIZE + Ke1MessageLen::<CS>::USIZE;
let state_len = Ke1StateLen::<CS>::USIZE;
let checked_slice =
check_slice_size(input, client_len + request_len + state_len, "client_login")?;
let ke1_state =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State::from_bytes(
ke1_state_bytes,
&checked_slice[client_len + request_len..],
)?;
Ok(Self {
oprf_client: voprf::NonVerifiableClient::deserialize(serialized_oprf_client)?,
oprf_client: voprf::NonVerifiableClient::deserialize(&checked_slice[..client_len])?,
credential_request: CredentialRequest::deserialize(
&checked_slice[client_len..client_len + request_len],
)?,
ke1_state,
credential_request: CredentialRequest::deserialize(serialized_credential_request)?,
})
}
/// Only used for testing zeroize
#[cfg(test)]
pub(crate) fn to_vec(&self) -> Vec<u8>
pub(crate) fn to_vec(&self) -> std::vec::Vec<u8>
where
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
{
[
self.oprf_client.serialize(),
self.oprf_client.serialize().to_vec(),
self.credential_request.serialize().to_vec(),
self.ke1_state.to_bytes().to_vec(),
]
@@ -461,7 +524,12 @@ impl<CS: CipherSuite> ClientLogin<CS> {
}
}
impl<CS: CipherSuite> ClientLogin<CS> {
impl<CS: CipherSuite> ClientLogin<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Returns an initial "blinded" password request to send to the server, as well as a ClientLogin
pub fn start<R: RngCore + CryptoRng>(
rng: &mut R,
@@ -489,14 +557,14 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// the server
pub fn finish(
self,
password: &[u8],
credential_response: CredentialResponse<CS>,
params: ClientLoginFinishParameters<CS>,
) -> Result<ClientLoginFinishResult<CS>, ProtocolError>
where
// 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>,
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
// Check if beta value from server is equal to alpha value from client
@@ -511,12 +579,13 @@ impl<CS: CipherSuite> ClientLogin<CS> {
}
let (_, randomized_pwd_hasher) = get_password_derived_key::<CS>(
password,
self.oprf_client.clone(),
credential_response.evaluation_element.clone(),
params.slow_hash,
)?;
let mut masking_key = GenericArray::<_, <CS::Hash as Digest>::OutputSize>::default();
let mut masking_key = Output::<CS::Hash>::default();
randomized_pwd_hasher
.expand(STR_MASKING_KEY, &mut masking_key)
.map_err(|_| InternalError::HkdfError)?;
@@ -585,7 +654,12 @@ impl<CS: CipherSuite> ClientLogin<CS> {
}
}
impl<CS: CipherSuite> ServerLogin<CS> {
impl<CS: CipherSuite> ServerLogin<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, Ke2StateLen<CS>> {
self.ke2_state.to_bytes()
@@ -617,9 +691,8 @@ impl<CS: CipherSuite> ServerLogin<CS> {
) -> Result<ServerLoginStartResult<CS>, ProtocolError<S::Error>>
where
// 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>,
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
let record = match password_file {
@@ -669,7 +742,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let server = voprf::NonVerifiableServer::new_with_key(&oprf_key)
.map_err(|e| ProtocolError::into_custom(e.into()))?;
let evaluate_result = server
.evaluate(credential_request.blinded_element, None)
.evaluate(&credential_request.blinded_element, None)
.map_err(|e| ProtocolError::into_custom(e.into()))?;
let evaluation_element = evaluate_result.message;
@@ -748,14 +821,24 @@ pub struct Identifiers<'a> {
/// Optional parameters for client registration finish
#[derive(DeriveWhere)]
#[derive_where(Clone, Default)]
pub struct ClientRegistrationFinishParameters<'i, 'h, CS: CipherSuite> {
pub struct ClientRegistrationFinishParameters<'i, 'h, CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Specifying the identifiers idU and idS
pub identifiers: Identifiers<'i>,
/// Specifying a configuration for the slow hash
pub slow_hash: Option<&'h CS::SlowHash>,
}
impl<'i, 'h, CS: CipherSuite> ClientRegistrationFinishParameters<'i, 'h, CS> {
impl<'i, 'h, CS: CipherSuite> ClientRegistrationFinishParameters<'i, 'h, CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Create a new [`ClientRegistrationFinishParameters`]
pub fn new(identifiers: Identifiers<'i>, slow_hash: Option<&'h CS::SlowHash>) -> Self {
Self {
@@ -768,7 +851,12 @@ impl<'i, 'h, CS: CipherSuite> ClientRegistrationFinishParameters<'i, 'h, CS> {
/// Contains the fields that are returned by a client registration start
#[derive(DeriveWhere)]
#[derive_where(Clone)]
pub struct ClientRegistrationStartResult<CS: CipherSuite> {
pub struct ClientRegistrationStartResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The registration request message to be sent to the server
pub message: RegistrationRequest<CS>,
/// The client state that must be persisted in order to complete registration
@@ -778,11 +866,16 @@ pub struct ClientRegistrationStartResult<CS: CipherSuite> {
/// Contains the fields that are returned by a client registration finish
#[derive(DeriveWhere)]
#[derive_where(Clone)]
pub struct ClientRegistrationFinishResult<CS: CipherSuite> {
pub struct ClientRegistrationFinishResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The registration upload message to be sent to the server
pub message: RegistrationUpload<CS>,
/// The export key output by client registration
pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub export_key: Output<CS::Hash>,
/// The server's static public key
pub server_s_pk: PublicKey<CS::KeGroup>,
/// Instance of the ClientRegistration, only used in tests for checking zeroize
@@ -790,17 +883,22 @@ pub struct ClientRegistrationFinishResult<CS: CipherSuite> {
pub state: ClientRegistration<CS>,
/// AuthKey, only used in tests
#[cfg(test)]
pub auth_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub auth_key: Output<CS::Hash>,
/// Password derived key, only used in tests
#[cfg(test)]
pub randomized_pwd: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub randomized_pwd: Output<CS::Hash>,
}
/// Contains the fields that are returned by a server registration start.
/// Note that there is no state output in this step
#[derive(DeriveWhere)]
#[derive_where(Clone)]
pub struct ServerRegistrationStartResult<CS: CipherSuite> {
pub struct ServerRegistrationStartResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The registration resposne message to send to the client
pub message: RegistrationResponse<CS>,
/// OPRF key, only used in tests
@@ -811,7 +909,12 @@ pub struct ServerRegistrationStartResult<CS: CipherSuite> {
/// Contains the fields that are returned by a client login start
#[derive(DeriveWhere)]
#[derive_where(Clone)]
pub struct ClientLoginStartResult<CS: CipherSuite> {
pub struct ClientLoginStartResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The message to send to the server to begin the login protocol
pub message: CredentialRequest<CS>,
/// The state that the client must keep in order to complete the protocol
@@ -821,7 +924,12 @@ pub struct ClientLoginStartResult<CS: CipherSuite> {
/// Optional parameters for client login finish
#[derive(DeriveWhere)]
#[derive_where(Clone, Default)]
pub struct ClientLoginFinishParameters<'c, 'i, 'h, CS: CipherSuite> {
pub struct ClientLoginFinishParameters<'c, 'i, 'h, CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Specifying a context field that the server must agree on
pub context: Option<&'c [u8]>,
/// Specifying a user identifier and server identifier that will be matched against the server
@@ -830,7 +938,12 @@ pub struct ClientLoginFinishParameters<'c, 'i, 'h, CS: CipherSuite> {
pub slow_hash: Option<&'h CS::SlowHash>,
}
impl<'c, 'i, 'h, CS: CipherSuite> ClientLoginFinishParameters<'c, 'i, 'h, CS> {
impl<'c, 'i, 'h, CS: CipherSuite> ClientLoginFinishParameters<'c, 'i, 'h, CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Create a new [`ClientLoginFinishParameters`]
pub fn new(
context: Option<&'c [u8]>,
@@ -848,13 +961,18 @@ impl<'c, 'i, 'h, CS: CipherSuite> ClientLoginFinishParameters<'c, 'i, 'h, CS> {
/// Contains the fields that are returned by a client login finish
#[derive(DeriveWhere)]
#[derive_where(Clone)]
pub struct ClientLoginFinishResult<CS: CipherSuite> {
pub struct ClientLoginFinishResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The message to send to the server to complete the protocol
pub message: CredentialFinalization<CS>,
/// The session key
pub session_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub session_key: Output<CS::Hash>,
/// The client-side export key
pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub export_key: Output<CS::Hash>,
/// The server's static public key
pub server_s_pk: PublicKey<CS::KeGroup>,
/// Instance of the ClientLogin, only used in tests for checking zeroize
@@ -862,10 +980,10 @@ pub struct ClientLoginFinishResult<CS: CipherSuite> {
pub state: ClientLogin<CS>,
/// Handshake secret, only used in tests
#[cfg(test)]
pub handshake_secret: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub handshake_secret: Output<CS::Hash>,
/// Client MAC key, only used in tests
#[cfg(test)]
pub client_mac_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub client_mac_key: Output<CS::Hash>,
}
/// Contains the fields that are returned by a server login finish
@@ -873,9 +991,14 @@ pub struct ClientLoginFinishResult<CS: CipherSuite> {
#[derive_where(Clone)]
#[cfg_attr(not(test), derive_where(Debug))]
#[cfg_attr(test, derive_where(Debug; ServerLogin<CS>))]
pub struct ServerLoginFinishResult<CS: CipherSuite> {
pub struct ServerLoginFinishResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The session key between client and server
pub session_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub session_key: Output<CS::Hash>,
_cs: PhantomData<CS>,
/// Instance of the ClientRegistration, only used in tests for checking zeroize
#[cfg(test)]
@@ -900,17 +1023,22 @@ pub struct ServerLoginStartParameters<'c, 'i> {
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State,
)]
pub struct ServerLoginStartResult<CS: CipherSuite> {
pub struct ServerLoginStartResult<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The message to send back to the client
pub message: CredentialResponse<CS>,
/// The state that the server must keep in order to finish the protocl
pub state: ServerLogin<CS>,
/// Handshake secret, only used in tests
#[cfg(test)]
pub handshake_secret: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub handshake_secret: Output<CS::Hash>,
/// Server MAC key, only used in tests
#[cfg(test)]
pub server_mac_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub server_mac_key: Output<CS::Hash>,
/// OPRF key, only used in tests
#[cfg(test)]
pub oprf_key: GenericArray<u8, <CS::OprfGroup as Group>::ScalarLen>,
@@ -922,20 +1050,19 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
////////////////////////////////////////////////
// Helper functions
#[allow(clippy::type_complexity)]
fn get_password_derived_key<CS: CipherSuite>(
input: &[u8],
oprf_client: voprf::NonVerifiableClient<CS::OprfGroup, CS::Hash>,
evaluation_element: voprf::EvaluationElement<CS::OprfGroup, CS::Hash>,
slow_hash: Option<&CS::SlowHash>,
) -> Result<
(
GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
Hkdf<CS::Hash>,
),
ProtocolError,
> {
let oprf_output = oprf_client.finalize(evaluation_element, None)?;
) -> Result<(Output<CS::Hash>, Hkdf<CS::Hash>), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let oprf_output = oprf_client.finalize(input, &evaluation_element, None)?;
let hardened_output = if let Some(slow_hash) = slow_hash {
slow_hash.hash(oprf_output.clone())
@@ -951,9 +1078,14 @@ fn get_password_derived_key<CS: CipherSuite>(
}
fn oprf_key_from_seed<G: Group, D: Hash>(
oprf_seed: &GenericArray<u8, D::OutputSize>,
oprf_seed: &Output<D>,
credential_identifier: &[u8],
) -> Result<GenericArray<u8, G::ScalarLen>, ProtocolError> {
) -> Result<GenericArray<u8, G::ScalarLen>, ProtocolError>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut ikm = GenericArray::<_, G::ScalarLen>::default();
Hkdf::<D>::from_prk(oprf_seed)
.ok()
@@ -963,7 +1095,7 @@ fn oprf_key_from_seed<G: Group, D: Hash>(
})
.ok_or(InternalError::HkdfError)?;
Ok(G::scalar_as_bytes(G::hash_to_scalar::<D, _, _>(
Some(ikm.as_slice()),
[ikm.as_slice()],
GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
)?))
}
@@ -971,23 +1103,31 @@ fn oprf_key_from_seed<G: Group, D: Hash>(
#[derive(DeriveWhere)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, PartialEq)]
pub(crate) struct MaskedResponse<CS: CipherSuite> {
pub(crate) struct MaskedResponse<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) nonce: GenericArray<u8, NonceLen>,
pub(crate) hash: GenericArray<u8, <CS::Hash as FixedOutput>::OutputSize>,
pub(crate) hash: Output<CS::Hash>,
pub(crate) pk: GenericArray<u8, <CS::KeGroup as KeGroup>::PkLen>,
}
#[allow(type_alias_bounds)]
pub(crate) type MaskedResponseLen<CS: CipherSuite> =
Sum<Sum<NonceLen, <CS::Hash as FixedOutput>::OutputSize>, <CS::KeGroup as KeGroup>::PkLen>;
Sum<Sum<NonceLen, OutputSize<CS::Hash>>, <CS::KeGroup as KeGroup>::PkLen>;
impl<CS: CipherSuite> MaskedResponse<CS> {
impl<CS: CipherSuite> MaskedResponse<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) fn serialize(&self) -> GenericArray<u8, MaskedResponseLen<CS>>
where
// 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>,
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
self.nonce.concat(self.hash.clone()).concat(self.pk.clone())
@@ -995,7 +1135,7 @@ impl<CS: CipherSuite> MaskedResponse<CS> {
pub(crate) fn deserialize(bytes: &[u8]) -> Self {
let nonce = NonceLen::USIZE;
let hash = nonce + <CS::Hash as FixedOutput>::OutputSize::USIZE;
let hash = nonce + OutputSize::<CS::Hash>::USIZE;
let pk = hash + <CS::KeGroup as KeGroup>::PkLen::USIZE;
Self {
@@ -1006,9 +1146,7 @@ impl<CS: CipherSuite> MaskedResponse<CS> {
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &[u8]> {
// MSRV: array `into_iter` isn't available in 1.51
#[allow(deprecated)]
IntoIter::new([self.nonce.as_slice(), &self.hash, &self.pk])
[self.nonce.as_slice(), &self.hash, &self.pk].into_iter()
}
}
@@ -1019,10 +1157,13 @@ fn mask_response<CS: CipherSuite>(
envelope: &Envelope<CS>,
) -> Result<MaskedResponse<CS>, ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// 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>,
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
let mut xor_pad = GenericArray::<_, MaskedResponseLen<CS>>::default();
@@ -1051,10 +1192,12 @@ fn unmask_response<CS: CipherSuite>(
masked_response: &MaskedResponse<CS>,
) -> Result<(PublicKey<CS::KeGroup>, Envelope<CS>), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// 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>,
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
let mut xor_pad = GenericArray::<_, MaskedResponseLen<CS>>::default();
@@ -1086,12 +1229,12 @@ pub(crate) fn bytestrings_from_identifiers<KG: KeGroup>(
server_s_pk: GenericArray<u8, KG::PkLen>,
) -> Result<(Serialize<U2, KG::PkLen>, Serialize<U2, KG::PkLen>), ProtocolError> {
let client_identity = if let Some(client) = ids.client {
Serialize::<U2, KG::PkLen>::from(client)?
Serialize::<U2, _>::from(client)?
} else {
Serialize::<U2, _>::from_owned(client_s_pk)?
};
let server_identity = if let Some(server) = ids.server {
Serialize::<U2, KG::PkLen>::from(server)?
Serialize::<U2, _>::from(server)?
} else {
Serialize::<U2, _>::from_owned(server_s_pk)?
};
@@ -1106,12 +1249,14 @@ pub(crate) fn bytestrings_from_identifiers<KG: KeGroup>(
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
rng: &mut R,
password: &[u8],
) -> Result<
voprf::NonVerifiableClientBlindResult<CS::OprfGroup, CS::Hash>,
voprf::errors::InternalError,
> {
) -> Result<voprf::NonVerifiableClientBlindResult<CS::OprfGroup, CS::Hash>, voprf::Error>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
#[cfg(not(test))]
let result = voprf::NonVerifiableClient::blind(password.to_vec(), rng)?;
let result = voprf::NonVerifiableClient::blind(password, rng)?;
#[cfg(test)]
let result = {
@@ -1127,7 +1272,7 @@ fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
true => (),
}
};
voprf::NonVerifiableClient::deterministic_blind_unchecked(password.to_vec(), blind)?
voprf::NonVerifiableClient::deterministic_blind_unchecked(password, blind)?
};
Ok(result)