From 88673d8e055a5ff2419774e409cd998546e067fe Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 4 Aug 2021 21:24:46 +0200 Subject: [PATCH] Separate AKE from OPRF take 2 (#222) * Separate AKE from OPRF Introduce X25519 implementation * Rename `AkeGroup` to `KeGroup` and `Group` to `OprfGroup` * Add documentation to "Overview" --- examples/digital_locker.rs | 3 +- examples/simple_login.rs | 3 +- src/ciphersuite.rs | 9 +- src/envelope.rs | 34 +++--- src/group/mod.rs | 1 + src/group/x25519.rs | 182 +++++++++++++++++++++++++++++++ src/key_exchange/tripledh.rs | 2 +- src/keypair.rs | 3 +- src/lib.rs | 52 ++++++--- src/messages.rs | 76 ++++++------- src/opaque.rs | 123 +++++++++++---------- src/serialization/tests.rs | 19 ++-- src/tests/full_test.rs | 19 ++-- src/tests/opaque_test_vectors.rs | 8 +- 14 files changed, 377 insertions(+), 157 deletions(-) create mode 100644 src/group/x25519.rs diff --git a/examples/digital_locker.rs b/examples/digital_locker.rs index 045f1f6..71ad641 100644 --- a/examples/digital_locker.rs +++ b/examples/digital_locker.rs @@ -44,7 +44,8 @@ use opaque_ke::{ #[allow(dead_code)] struct Default; impl CipherSuite for Default { - type Group = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; + type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; type Hash = sha2::Sha512; type SlowHash = opaque_ke::slow_hash::NoOpHash; diff --git a/examples/simple_login.rs b/examples/simple_login.rs index f8f42e0..c380ba1 100644 --- a/examples/simple_login.rs +++ b/examples/simple_login.rs @@ -37,7 +37,8 @@ use opaque_ke::{ #[allow(dead_code)] struct Default; impl CipherSuite for Default { - type Group = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; + type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; type Hash = sha2::Sha512; type SlowHash = opaque_ke::slow_hash::NoOpHash; diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs index 7e49829..c6be548 100644 --- a/src/ciphersuite.rs +++ b/src/ciphersuite.rs @@ -8,9 +8,10 @@ use crate::{group::Group, hash::Hash, key_exchange::traits::KeyExchange, slow_hash::SlowHash}; /// Configures the underlying primitives used in OPAQUE -/// * `Group`: a finite cyclic group along with a point representation, along +/// * `OprfGroup`: a finite cyclic group along with a point representation, along /// with an extension trait PasswordToCurve that allows some customization on /// how to hash a password to a curve point. See `group::Group`. +/// * `KeGroup`: A `Group` used for the `KeyExchange`. /// * `KeyExchange`: The key exchange protocol to use in the login step /// * `Hash`: The main hashing function to use /// * `SlowHash`: A slow hashing function, typically used for password hashing @@ -18,9 +19,11 @@ pub trait CipherSuite { /// A finite cyclic group along with a point representation along with /// an extension trait PasswordToCurve that allows some customization on /// how to hash a password to a curve point. See `group::Group`. - type Group: Group; + type OprfGroup: Group; + /// A `Group` used for the `KeyExchange`. + type KeGroup: Group; /// A key exchange protocol - type KeyExchange: KeyExchange; + type KeyExchange: KeyExchange; /// The main hash function use (for HKDF computations and hashing transcripts) type Hash: Hash; /// A slow hashing function, typically used for password hashing diff --git a/src/envelope.rs b/src/envelope.rs index aae79eb..0f776f6 100644 --- a/src/envelope.rs +++ b/src/envelope.rs @@ -31,15 +31,17 @@ const NONCE_LEN: usize = 32; fn build_inner_envelope_internal( random_pwd: &[u8], nonce: &[u8], -) -> Result, ProtocolError> { +) -> Result, ProtocolError> { let h = Hkdf::::new(None, random_pwd); - let mut keypair_seed = vec![0u8; as SizedBytes>::Len::to_usize()]; + let mut keypair_seed = vec![0u8; as SizedBytes>::Len::to_usize()]; h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed) .map_err(|_| InternalPakeError::HkdfError)?; - let client_static_keypair = - KeyPair::::from_private_key_slice(&CS::Group::scalar_as_bytes( - CS::Group::hash_to_scalar::(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?, - ))?; + let client_static_keypair = KeyPair::::from_private_key_slice( + &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::( + &keypair_seed[..], + STR_OPAQUE_HASH_TO_SCALAR, + )?), + )?; Ok(client_static_keypair.public().clone()) } @@ -47,15 +49,17 @@ fn build_inner_envelope_internal( fn recover_keys_internal( random_pwd: &[u8], nonce: &[u8], -) -> Result, ProtocolError> { +) -> Result, ProtocolError> { let h = Hkdf::::new(None, random_pwd); - let mut keypair_seed = vec![0u8; as SizedBytes>::Len::to_usize()]; + let mut keypair_seed = vec![0u8; as SizedBytes>::Len::to_usize()]; h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed) .map_err(|_| InternalPakeError::HkdfError)?; - let client_static_keypair = - KeyPair::::from_private_key_slice(&CS::Group::scalar_as_bytes( - CS::Group::hash_to_scalar::(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?, - ))?; + let client_static_keypair = KeyPair::::from_private_key_slice( + &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::( + &keypair_seed[..], + STR_OPAQUE_HASH_TO_SCALAR, + )?), + )?; Ok(client_static_keypair) } @@ -110,7 +114,7 @@ impl_debug_eq_hash_for!(struct Envelope, [mode, nonce, hmac]); // key. This key is also used to derive the export_key parameter, which is technically // unrelated to the envelope's encrypted and authenticated contents. pub(crate) struct OpenedEnvelope { - pub(crate) client_static_keypair: KeyPair, + pub(crate) client_static_keypair: KeyPair, pub(crate) export_key: GenericArray::OutputSize>, pub(crate) id_u: Vec, pub(crate) id_s: Vec, @@ -134,13 +138,13 @@ type SealRawResult = ( #[cfg(not(test))] type SealResult = ( Envelope, - PublicKey<::Group>, + PublicKey<::KeGroup>, GenericArray::Hash as Digest>::OutputSize>, ); #[cfg(test)] type SealResult = ( Envelope, - PublicKey<::Group>, + PublicKey<::KeGroup>, GenericArray::Hash as Digest>::OutputSize>, Vec, ); diff --git a/src/group/mod.rs b/src/group/mod.rs index d1ebec4..41e3901 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -10,6 +10,7 @@ mod expand; #[cfg(feature = "p256")] pub(crate) mod p256; mod ristretto; +mod x25519; use crate::errors::{InternalPakeError, ProtocolError}; use crate::hash::Hash; diff --git a/src/group/x25519.rs b/src/group/x25519.rs new file mode 100644 index 0000000..cf9543c --- /dev/null +++ b/src/group/x25519.rs @@ -0,0 +1,182 @@ +// 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. + +use super::Group; +use crate::errors::{InternalPakeError, ProtocolError}; +use crate::hash::Hash; +use curve25519_dalek::{constants::X25519_BASEPOINT, montgomery::MontgomeryPoint, scalar::Scalar}; +use generic_array::{typenum::U32, GenericArray}; +use rand::{CryptoRng, RngCore}; + +/// The implementation of such a subgroup for Ristretto +impl Group for MontgomeryPoint { + const SUITE_ID: usize = 0xFFFF; + + fn map_to_curve(_msg: &[u8], _dst: &[u8]) -> Result { + unreachable!("this algorithm should only be used as the `KeGroup`") + } + + fn hash_to_scalar(_input: &[u8], _dst: &[u8]) -> Result { + unreachable!("this algorithm should only be used as the `KeGroup`") + } + + type Scalar = Scalar; + type ScalarLen = U32; + fn from_scalar_slice( + scalar_bits: &GenericArray, + ) -> Result { + Ok(Scalar::from_bytes_mod_order(*scalar_bits.as_ref())) + } + fn random_nonzero_scalar(rng: &mut R) -> Self::Scalar { + loop { + let scalar = { + #[cfg(not(test))] + { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) + } + + // Tests need an exact conversion from bytes to scalar, sampling only 32 bytes from rng + #[cfg(test)] + { + let mut scalar_bytes = [0u8; 32]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order(scalar_bytes) + } + }; + + if scalar != Scalar::zero() { + break scalar; + } + } + } + fn scalar_as_bytes(scalar: Self::Scalar) -> GenericArray { + scalar.to_bytes().into() + } + fn scalar_invert(_scalar: &Self::Scalar) -> Self::Scalar { + unreachable!("this algorithm should only be used as the `KeGroup`") + } + + // The byte length necessary to represent group elements + type ElemLen = U32; + fn from_element_slice( + element_bits: &GenericArray, + ) -> Result { + Ok(Self(*element_bits.as_ref())) + } + // serialization of a group element + fn to_arr(&self) -> GenericArray { + self.to_bytes().into() + } + + fn base_point() -> Self { + X25519_BASEPOINT + } + + fn mult_by_slice(&self, scalar: &GenericArray) -> Self { + self * Scalar::from_bits(*scalar.as_ref()) + } + + /// Returns if the group element is equal to the identity (1) + fn is_identity(&self) -> bool { + unreachable!("this algorithm should only be used as the `KeGroup`") + } + + fn ct_equal(&self, _other: &Self) -> bool { + unreachable!("this algorithm should only be used as the `KeGroup`") + } +} + +#[test] +fn test() -> Result<(), ProtocolError> { + use crate::{ + errors::PakeError, key_exchange::tripledh::TripleDH, slow_hash::NoOpHash, CipherSuite, + ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult, ClientLoginStartResult, + ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult, + ClientRegistrationStartResult, ServerLogin, ServerLoginStartParameters, + ServerLoginStartResult, ServerRegistration, ServerSetup, + }; + use curve25519_dalek::ristretto::RistrettoPoint; + use rand::rngs::OsRng; + + struct X25519Sha512NoSlowHash; + impl CipherSuite for X25519Sha512NoSlowHash { + type OprfGroup = RistrettoPoint; + type KeGroup = MontgomeryPoint; + type KeyExchange = TripleDH; + type Hash = sha2::Sha512; + type SlowHash = NoOpHash; + } + + const PASSWORD: &[u8] = b"1234"; + + let server_setup = ServerSetup::::new(&mut OsRng); + + let ClientRegistrationStartResult { + message, + state: client, + } = ClientRegistration::start(&mut OsRng, PASSWORD)?; + let message = ServerRegistration::start(&server_setup, message, &[])?.message; + let ClientRegistrationFinishResult { + message, + export_key: register_export_key, + .. + } = client.finish( + &mut OsRng, + message, + ClientRegistrationFinishParameters::Default, + )?; + let server_registration = ServerRegistration::finish(message); + + let ClientLoginStartResult { + message, + state: client, + } = ClientLogin::start(&mut OsRng, PASSWORD)?; + let ServerLoginStartResult { + message, + state: server, + .. + } = ServerLogin::start( + &mut OsRng, + &server_setup, + Some(server_registration), + message, + &[], + ServerLoginStartParameters::default(), + )?; + let ClientLoginFinishResult { + message, + session_key: client_session_key, + export_key: login_export_key, + .. + } = client.finish(message, ClientLoginFinishParameters::Default)?; + let server_session_key = server.finish(message)?.session_key; + + assert_eq!(register_export_key, login_export_key); + assert_eq!(client_session_key, server_session_key); + + let ClientLoginStartResult { + message, + state: client, + } = ClientLogin::start(&mut OsRng, PASSWORD)?; + let ServerLoginStartResult { message, .. } = ServerLogin::start( + &mut OsRng, + &server_setup, + None, + message, + &[], + ServerLoginStartParameters::default(), + )?; + + assert!(matches!( + client.finish(message, ClientLoginFinishParameters::Default), + Err(ProtocolError::VerificationError( + PakeError::InvalidLoginError + )) + )); + + Ok(()) +} diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 616ec8c..aa29294 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -411,7 +411,7 @@ impl> FromBytes for Ke2Message { )?; // Check the public key bytes - let server_e_pk = KeyPair::::check_public_key(PublicKey::from_bytes( + let server_e_pk = KeyPair::::check_public_key(PublicKey::from_bytes( &unchecked_server_e_pk[..key_len], )?)?; diff --git a/src/keypair.rs b/src/keypair.rs index b40bdb0..f81410b 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -462,7 +462,8 @@ mod tests { struct Default; impl CipherSuite for Default { - type Group = RistrettoPoint; + type OprfGroup = RistrettoPoint; + type KeGroup = RistrettoPoint; type KeyExchange = crate::key_exchange::tripledh::TripleDH; type Hash = sha2::Sha512; type SlowHash = crate::slow_hash::NoOpHash; diff --git a/src/lib.rs b/src/lib.rs index 031a18e..8c81542 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,9 @@ //! //! OPAQUE is a protocol between a client and a server. They must first agree on a collection of primitives //! to be kept consistent throughout protocol execution. These include: -//! * a finite cyclic group along with a point representation, +//! * a finite cyclic group along with a point representation +//! * for the OPRF and +//! * for the key exchange //! * a key exchange protocol, //! * a hashing function, and //! * a slow hashing function. @@ -26,7 +28,8 @@ //! use opaque_ke::CipherSuite; //! struct Default; //! impl CipherSuite for Default { -//! type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! type Hash = sha2::Sha512; //! type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -47,7 +50,8 @@ //! # use opaque_ke::ServerSetup; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -79,7 +83,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -109,7 +114,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -146,7 +152,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -184,7 +191,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -226,7 +234,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -259,7 +268,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -312,7 +322,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -357,7 +368,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -432,7 +444,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -509,7 +522,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -574,7 +588,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -611,7 +626,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -660,7 +676,8 @@ //! # use opaque_ke::CipherSuite; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; @@ -737,7 +754,8 @@ //! # use zeroize::Zeroize; //! # struct Default; //! # impl CipherSuite for Default { -//! # type Group = RistrettoPoint; +//! # type OprfGroup = RistrettoPoint; +//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; //! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; diff --git a/src/messages.rs b/src/messages.rs index 9e67209..00b7deb 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -28,13 +28,13 @@ use rand::{CryptoRng, RngCore}; /// The message sent by the client to the server, to initiate registration pub struct RegistrationRequest { /// blinded password information - pub(crate) alpha: CS::Group, + pub(crate) alpha: CS::OprfGroup, } impl RegistrationRequest { /// Only used for testing purposes #[cfg(test)] - pub fn get_alpha_for_testing(&self) -> CS::Group { + pub fn get_alpha_for_testing(&self) -> CS::OprfGroup { self.alpha } } @@ -46,7 +46,7 @@ impl Clone for RegistrationRequest { } } -impl_debug_eq_hash_for!(struct RegistrationRequest, [alpha], [CS::Group]); +impl_debug_eq_hash_for!(struct RegistrationRequest, [alpha], [CS::OprfGroup]); impl RegistrationRequest { /// Serialization into bytes @@ -56,12 +56,12 @@ impl RegistrationRequest { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::to_usize(); + 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)?; + let alpha = CS::OprfGroup::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if alpha.is_identity() { @@ -77,9 +77,9 @@ impl_serialize_and_deserialize_for!(RegistrationRequest); /// registration attempt pub struct RegistrationResponse { /// The server's oprf output - pub(crate) beta: CS::Group, + pub(crate) beta: CS::OprfGroup, /// Server's static public key - pub(crate) server_s_pk: PublicKey, + pub(crate) server_s_pk: PublicKey, } // Cannot be derived because it would require for CS to be Clone. @@ -95,7 +95,7 @@ impl Clone for RegistrationResponse { impl_debug_eq_hash_for!( struct RegistrationResponse, [beta, server_s_pk], - [CS::Group], + [CS::OprfGroup], ); impl RegistrationResponse { @@ -106,15 +106,15 @@ impl RegistrationResponse { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::to_usize(); - let key_len = as SizedBytes>::Len::to_usize(); + let elem_len = ::ElemLen::to_usize(); + let key_len = as SizedBytes>::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)?; + let beta = CS::OprfGroup::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if beta.is_identity() { @@ -122,7 +122,7 @@ impl RegistrationResponse { } // Ensure that public key is valid - let server_s_pk = KeyPair::::check_public_key(PublicKey::from_bytes( + let server_s_pk = KeyPair::::check_public_key(PublicKey::from_bytes( &checked_slice[elem_len..], )?)?; @@ -132,7 +132,7 @@ impl RegistrationResponse { #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the reflection /// error case - pub fn set_beta_for_testing(&self, new_beta: CS::Group) -> Self { + pub fn set_beta_for_testing(&self, new_beta: CS::OprfGroup) -> Self { Self { beta: new_beta, server_s_pk: self.server_s_pk.clone(), @@ -151,7 +151,7 @@ pub struct RegistrationUpload { /// 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, + pub(crate) client_s_pk: PublicKey, } impl_clone_for!( @@ -176,7 +176,7 @@ impl RegistrationUpload { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let key_len = as SizedBytes>::Len::to_usize(); + let key_len = as SizedBytes>::Len::to_usize(); let hash_len = ::OutputSize::to_usize(); let checked_slice = check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?; @@ -186,14 +186,14 @@ impl RegistrationUpload { masking_key: GenericArray::clone_from_slice( &checked_slice[key_len..key_len + hash_len], ), - client_s_pk: KeyPair::::check_public_key(PublicKey::from_bytes( + 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>( + pub(crate) fn dummy>( rng: &mut R, server_setup: &ServerSetup, ) -> Self { @@ -213,8 +213,8 @@ 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, + pub(crate) alpha: CS::OprfGroup, + pub(crate) ke1_message: >::KE1Message, } // Cannot be derived because it would require for CS to be Clone. @@ -231,8 +231,8 @@ impl_debug_eq_hash_for!( struct CredentialRequest, [alpha, ke1_message], [ - CS::Group, - >::KE1Message + CS::OprfGroup, + >::KE1Message ], ); @@ -244,14 +244,14 @@ impl CredentialRequest { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::to_usize(); + 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)?; + let alpha = CS::OprfGroup::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if alpha.is_identity() { @@ -259,7 +259,7 @@ impl CredentialRequest { } let ke1_message = - >::KE1Message::from_bytes::( + >::KE1Message::from_bytes::( &checked_slice[elem_len..], )?; @@ -268,7 +268,7 @@ impl CredentialRequest { /// Only used for testing purposes #[cfg(test)] - pub fn get_alpha_for_testing(&self) -> CS::Group { + pub fn get_alpha_for_testing(&self) -> CS::OprfGroup { self.alpha } } @@ -279,10 +279,10 @@ impl_serialize_and_deserialize_for!(CredentialRequest); /// login attempt pub struct CredentialResponse { /// the server's oprf output - pub(crate) beta: CS::Group, + pub(crate) beta: CS::OprfGroup, pub(crate) masking_nonce: Vec, pub(crate) masked_response: Vec, - pub(crate) ke2_message: >::KE2Message, + pub(crate) ke2_message: >::KE2Message, } // Cannot be derived because it would require for CS to be Clone. @@ -301,8 +301,8 @@ impl_debug_eq_hash_for!( struct CredentialResponse, [beta, masking_nonce, masked_response, ke2_message], [ - CS::Group, - >::KE2Message, + CS::OprfGroup, + >::KE2Message, ], ); @@ -317,7 +317,7 @@ impl CredentialResponse { } pub(crate) fn serialize_without_ke( - beta: &CS::Group, + beta: &CS::OprfGroup, masking_nonce: &[u8], masked_response: &[u8], ) -> Vec { @@ -326,8 +326,8 @@ impl CredentialResponse { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::to_usize(); - let key_len = as SizedBytes>::Len::to_usize(); + let elem_len = ::ElemLen::to_usize(); + let key_len = as SizedBytes>::Len::to_usize(); let nonce_len: usize = 32; let envelope_len = Envelope::::len(); let masked_response_len = key_len + envelope_len; @@ -343,7 +343,7 @@ impl CredentialResponse { // correct subgroup let beta_bytes = &checked_slice[..elem_len]; let arr = GenericArray::from_slice(beta_bytes); - let beta = CS::Group::from_element_slice(arr)?; + let beta = CS::OprfGroup::from_element_slice(arr)?; // Throw an error if the identity group element is encountered if beta.is_identity() { @@ -355,7 +355,7 @@ impl CredentialResponse { [elem_len + nonce_len..elem_len + nonce_len + masked_response_len] .to_vec(); let ke2_message = - >::KE2Message::from_bytes::( + >::KE2Message::from_bytes::( &checked_slice[elem_len + nonce_len + masked_response_len..], )?; @@ -370,7 +370,7 @@ impl CredentialResponse { #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the reflection /// error case - pub fn set_beta_for_testing(&self, new_beta: CS::Group) -> Self { + pub fn set_beta_for_testing(&self, new_beta: CS::OprfGroup) -> Self { Self { beta: new_beta, masking_nonce: self.masking_nonce.clone(), @@ -385,14 +385,14 @@ 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, + pub(crate) ke3_message: >::KE3Message, } impl_clone_for!(struct CredentialFinalization, [ke3_message]); impl_debug_eq_hash_for!( struct CredentialFinalization, [ke3_message], - [>::KE3Message], + [>::KE3Message], ); impl CredentialFinalization { @@ -404,7 +404,7 @@ impl CredentialFinalization { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let ke3_message = - >::KE3Message::from_bytes::( + >::KE3Message::from_bytes::( input, )?; Ok(Self { ke3_message }) diff --git a/src/opaque.rs b/src/opaque.rs index dc86873..fd4c538 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -40,32 +40,32 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8] = b"OPAQUE-DeriveKeyPair"; feature = "serialize", derive(serde::Deserialize, serde::Serialize), serde(bound( - deserialize = "KeyPair: serde::Deserialize<'de>", - serialize = "KeyPair: serde::Serialize" + deserialize = "KeyPair: serde::Deserialize<'de>", + serialize = "KeyPair: serde::Serialize" )) )] pub struct ServerSetup< CS: CipherSuite, - S: SecretKey = PrivateKey<::Group>, + S: SecretKey = PrivateKey<::KeGroup>, > { oprf_seed: GenericArray::OutputSize>, - keypair: KeyPair, - pub(crate) fake_keypair: KeyPair, + keypair: KeyPair, + pub(crate) fake_keypair: KeyPair, } -impl ServerSetup> { +impl ServerSetup> { /// Generate a new instance of server setup pub fn new(rng: &mut R) -> Self { - let keypair = KeyPair::::generate_random(rng); + let keypair = KeyPair::::generate_random(rng); Self::new_with_key(rng, keypair) } } -impl> ServerSetup { +impl> ServerSetup { /// Create [`ServerSetup`] with the given keypair pub fn new_with_key( rng: &mut R, - keypair: KeyPair, + keypair: KeyPair, ) -> Self { let mut seed = vec![0u8; ::OutputSize::to_usize()]; rng.fill_bytes(&mut seed); @@ -73,7 +73,7 @@ impl> ServerSetup { Self { oprf_seed: GenericArray::clone_from_slice(&seed[..]), keypair, - fake_keypair: KeyPair::::generate_random(rng), + fake_keypair: KeyPair::::generate_random(rng), } } @@ -90,7 +90,7 @@ impl> ServerSetup { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result> { let seed_len = ::OutputSize::to_usize(); - let key_len = as SizedBytes>::Len::to_usize(); + let key_len = as SizedBytes>::Len::to_usize(); let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")?; Ok(Self { @@ -102,7 +102,7 @@ impl> ServerSetup { } /// Returns the keypair - pub fn keypair(&self) -> &KeyPair { + pub fn keypair(&self) -> &KeyPair { &self.keypair } } @@ -122,16 +122,16 @@ impl_debug_eq_hash_for!( /// The state elements the client holds to register itself pub struct ClientRegistration { - alpha: CS::Group, + alpha: CS::OprfGroup, /// token containing the client's password and the blinding factor - pub(crate) token: oprf::Token, + pub(crate) token: oprf::Token, } impl_clone_for!(struct ClientRegistration, [token, alpha]); impl_debug_eq_hash_for!( struct ClientRegistration, [token], - [oprf::Token], + [oprf::Token], ); impl ClientRegistration { @@ -139,7 +139,7 @@ impl ClientRegistration { pub fn serialize(&self) -> Vec { [ &self.alpha.to_arr().to_vec(), - &CS::Group::scalar_as_bytes(self.token.blind)[..], + &CS::OprfGroup::scalar_as_bytes(self.token.blind)[..], &self.token.data, ] .concat() @@ -147,8 +147,8 @@ impl ClientRegistration { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::to_usize(); - let scalar_len = ::ScalarLen::to_usize(); + let elem_len = ::ElemLen::to_usize(); + let scalar_len = ::ScalarLen::to_usize(); let min_expected_len = elem_len + scalar_len; let checked_slice = (if input.len() <= min_expected_len { Err(InternalPakeError::SizeError { @@ -160,14 +160,15 @@ impl ClientRegistration { Ok(input) })?; - let alpha = - CS::Group::from_element_slice(GenericArray::from_slice(&checked_slice[..elem_len]))?; + let alpha = CS::OprfGroup::from_element_slice(GenericArray::from_slice( + &checked_slice[..elem_len], + ))?; // Check that the message is actually containing an element of the // correct subgroup let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[elem_len..elem_len + scalar_len]); - let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?; + let blinding_factor = CS::OprfGroup::from_scalar_slice(blinding_factor_bytes)?; let password = checked_slice[elem_len + scalar_len..].to_vec(); Ok(Self { @@ -257,7 +258,8 @@ impl ClientRegistration { blinding_factor_rng: &mut R, password: &[u8], ) -> Result, ProtocolError> { - let (token, alpha) = oprf::blind::(password, blinding_factor_rng)?; + let (token, alpha) = + oprf::blind::(password, blinding_factor_rng)?; Ok(ClientRegistrationStartResult { message: RegistrationRequest:: { alpha }, @@ -273,7 +275,7 @@ pub struct ClientRegistrationFinishResult { /// The export key output by client registration pub export_key: GenericArray::OutputSize>, /// The server's static public key - pub server_s_pk: PublicKey, + pub server_s_pk: PublicKey, /// Instance of the ClientRegistration, only used in tests for checking zeroize #[cfg(test)] pub state: ClientRegistration, @@ -321,8 +323,10 @@ impl ClientRegistration { return Err(ProtocolError::ReflectedValueError); } - let password_derived_key = - get_password_derived_key::(&self.token, r2.beta)?; + let password_derived_key = get_password_derived_key::( + &self.token, + r2.beta, + )?; #[cfg_attr(not(test), allow(unused_variables))] let (randomized_pwd, h) = Hkdf::::extract(None, &password_derived_key); @@ -358,7 +362,7 @@ pub struct ServerRegistrationStartResult { pub message: RegistrationResponse, /// OPRF key, only used in tests #[cfg(test)] - pub oprf_key: GenericArray::ScalarLen>, + pub oprf_key: GenericArray::ScalarLen>, } // Cannot be derived because it would require for CS to be Clone. @@ -403,18 +407,18 @@ impl ServerRegistration { /// From the client's "blinded" password, returns a response to be /// sent back to the client, as well as a ServerRegistration - pub fn start>( + pub fn start>( server_setup: &ServerSetup, message: RegistrationRequest, credential_identifier: &[u8], ) -> Result, ProtocolError> { - let oprf_key = oprf_key_from_seed::( + let oprf_key = oprf_key_from_seed::( &server_setup.oprf_seed, credential_identifier, )?; // Compute beta = alpha^oprf_key - let beta = oprf::evaluate::(message.alpha, &oprf_key); + let beta = oprf::evaluate::(message.alpha, &oprf_key); Ok(ServerRegistrationStartResult { message: RegistrationResponse { @@ -422,7 +426,7 @@ impl ServerRegistration { server_s_pk: server_setup.keypair.public().clone(), }, #[cfg(test)] - oprf_key: CS::Group::scalar_as_bytes(oprf_key), + oprf_key: CS::OprfGroup::scalar_as_bytes(oprf_key), }) } @@ -433,7 +437,7 @@ impl ServerRegistration { } // Creates a dummy instance used for faking a [CredentialResponse] - pub(crate) fn dummy>( + pub(crate) fn dummy>( rng: &mut R, server_setup: &ServerSetup, ) -> Self { @@ -451,14 +455,14 @@ impl_serialize_and_deserialize_for!(ServerRegistration); #[cfg_attr( feature = "serialize", serde(bound( - deserialize = "oprf::Token: serde::Deserialize<'de>, >::KE1State: serde::Deserialize<'de>", - serialize = "oprf::Token: serde::Serialize, >::KE1State: serde::Serialize" + deserialize = "oprf::Token: serde::Deserialize<'de>, >::KE1State: serde::Deserialize<'de>", + serialize = "oprf::Token: serde::Serialize, >::KE1State: serde::Serialize" )) )] pub struct ClientLogin { /// token containing the client's password and the blinding factor - token: oprf::Token, - ke1_state: >::KE1State, + token: oprf::Token, + ke1_state: >::KE1State, serialized_credential_request: Vec, } @@ -466,14 +470,14 @@ impl_clone_for!(struct ClientLogin, [token, ke1_state, serializ impl_debug_eq_hash_for!( struct ClientLogin, [token, ke1_state, serialized_credential_request], - [oprf::Token, >::KE1State], + [oprf::Token, >::KE1State], ); impl ClientLogin { /// Serialization into bytes pub fn serialize(&self) -> Result, ProtocolError> { let output: Vec = [ - &CS::Group::scalar_as_bytes(self.token.blind)[..], + &CS::OprfGroup::scalar_as_bytes(self.token.blind)[..], &serialize(&self.serialized_credential_request, 2)?, &serialize(&self.ke1_state.to_bytes(), 2)?, &self.token.data, @@ -484,7 +488,7 @@ impl ClientLogin { /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let scalar_len = ::ScalarLen::to_usize(); + let scalar_len = ::ScalarLen::to_usize(); let checked_slice = (if input.len() <= scalar_len { Err(InternalPakeError::SizeError { name: "client_login_bytes", @@ -496,13 +500,13 @@ impl ClientLogin { })?; let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[..scalar_len]); - let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?; + let blinding_factor = CS::OprfGroup::from_scalar_slice(blinding_factor_bytes)?; let (serialized_credential_request, remainder) = tokenize(&checked_slice[scalar_len..], 2)?; let (ke1_state_bytes, password) = tokenize(&remainder, 2)?; let ke1_state = - >::KE1State::from_bytes::( + >::KE1State::from_bytes::( &ke1_state_bytes[..], )?; Ok(Self { @@ -575,7 +579,7 @@ pub struct ClientLoginFinishResult { /// The client-side export key pub export_key: GenericArray::OutputSize>, /// The server's static public key - pub server_s_pk: PublicKey, + pub server_s_pk: PublicKey, /// Instance of the ClientLogin, only used in tests for checking zeroize #[cfg(test)] pub state: ClientLogin, @@ -611,7 +615,7 @@ impl ClientLogin { rng: &mut R, password: &[u8], ) -> Result, ProtocolError> { - let (token, alpha) = oprf::blind::(password, rng)?; + let (token, alpha) = oprf::blind::(password, rng)?; let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(rng)?; @@ -652,7 +656,7 @@ impl ClientLogin { return Err(ProtocolError::ReflectedValueError); } - let password_derived_key = get_password_derived_key::( + let password_derived_key = get_password_derived_key::( &self.token, credential_response.beta, )?; @@ -722,7 +726,7 @@ impl ClientLogin { /// The state elements the server holds to record a login pub struct ServerLogin { - ke2_state: >::KE2State, + ke2_state: >::KE2State, _cs: PhantomData, } @@ -730,7 +734,7 @@ impl_clone_for!(struct ServerLogin, [ke2_state, _cs]); impl_debug_eq_hash_for!( struct ServerLogin, [ke2_state, _cs], - [>::KE2State], + [>::KE2State], ); /// Optional parameters for server login start @@ -766,7 +770,7 @@ pub struct ServerLoginStartResult { pub server_mac_key: GenericArray::OutputSize>, /// OPRF key, only used in tests #[cfg(test)] - pub oprf_key: GenericArray::ScalarLen>, + pub oprf_key: GenericArray::ScalarLen>, } // Cannot be derived because it would require for CS to be Clone. @@ -817,15 +821,16 @@ impl ServerLogin { pub fn deserialize(bytes: &[u8]) -> Result { Ok(Self { _cs: PhantomData, - ke2_state: >::KE2State::from_bytes::< - CS, - >(bytes)?, + ke2_state: + >::KE2State::from_bytes::( + bytes, + )?, }) } /// From the client's "blinded" password, returns a challenge to be /// sent back to the client, as well as a ServerLogin - pub fn start>( + pub fn start>( rng: &mut R, server_setup: &ServerSetup, password_file: Option>, @@ -871,7 +876,7 @@ impl ServerLogin { let l1_bytes = &l1.serialize(); - let oprf_key = oprf_key_from_seed::( + let oprf_key = oprf_key_from_seed::( &server_setup.oprf_seed, credential_identifier, ) @@ -911,7 +916,7 @@ impl ServerLogin { #[cfg(test)] server_mac_key: result.3, #[cfg(test)] - oprf_key: CS::Group::scalar_as_bytes(oprf_key), + oprf_key: CS::OprfGroup::scalar_as_bytes(oprf_key), }) } @@ -921,7 +926,7 @@ impl ServerLogin { self, message: CredentialFinalization, ) -> Result, ProtocolError> { - let session_key = >::finish_ke( + let session_key = >::finish_ke( message.ke3_message, &self.ke2_state, ) @@ -1033,11 +1038,11 @@ fn oprf_key_from_seed( fn mask_response( masking_key: &[u8], masking_nonce: &[u8], - server_s_pk: &PublicKey, + server_s_pk: &PublicKey, envelope: &Envelope, ) -> Result, ProtocolError> { let mut xor_pad = - vec![0u8; as SizedBytes>::Len::to_usize() + Envelope::::len()]; + vec![0u8; as SizedBytes>::Len::to_usize() + Envelope::::len()]; Hkdf::::from_prk(masking_key) .map_err(|_| InternalPakeError::HkdfError)? .expand( @@ -1059,9 +1064,9 @@ fn unmask_response( masking_key: &[u8], masking_nonce: &[u8], masked_response: &[u8], -) -> Result<(PublicKey, Envelope), ProtocolError> { +) -> Result<(PublicKey, Envelope), ProtocolError> { let mut xor_pad = - vec![0u8; as SizedBytes>::Len::to_usize() + Envelope::::len()]; + vec![0u8; as SizedBytes>::Len::to_usize() + Envelope::::len()]; Hkdf::::from_prk(masking_key) .map_err(|_| InternalPakeError::HkdfError)? .expand( @@ -1074,13 +1079,13 @@ fn unmask_response( .zip(masked_response.iter()) .map(|(&x1, &x2)| x1 ^ x2) .collect(); - let key_len = as SizedBytes>::Len::to_usize(); + let key_len = as SizedBytes>::Len::to_usize(); let unchecked_server_s_pk = PublicKey::from_arr(&GenericArray::clone_from_slice(&plaintext[..key_len]))?; let envelope = Envelope::deserialize(&plaintext[key_len..])?; // Ensure that public key is valid - let server_s_pk = KeyPair::::check_public_key(unchecked_server_s_pk) + let server_s_pk = KeyPair::::check_public_key(unchecked_server_s_pk) .map_err(|_| ProtocolError::VerificationError(PakeError::SerializationError))?; Ok((server_s_pk, envelope)) diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs index 6f096ad..468fd01 100644 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -27,7 +27,8 @@ use sha2::Digest; struct Default; impl CipherSuite for Default { - type Group = RistrettoPoint; + type OprfGroup = RistrettoPoint; + type KeGroup = RistrettoPoint; type KeyExchange = TripleDH; type Hash = sha2::Sha512; type SlowHash = crate::slow_hash::NoOpHash; @@ -78,7 +79,7 @@ fn server_registration_roundtrip() { // mock_envelope_bytes.extend_from_slice(&ciphertext); // ciphertext which is an encrypted private key mock_envelope_bytes.extend_from_slice(&[0; MAC_SIZE]); // length-MAC_SIZE hmac - let mock_client_kp = KeyPair::<::Group>::generate_random(&mut rng); + let mock_client_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); // serialization order: oprf_key, public key, envelope let mut bytes = Vec::::new(); bytes.extend_from_slice(&mock_client_kp.public().to_arr()); @@ -118,7 +119,7 @@ fn registration_response_roundtrip() { let pt = random_ristretto_point(); let beta_bytes = pt.to_arr(); let mut rng = OsRng; - let skp = KeyPair::<::Group>::generate_random(&mut rng); + let skp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let pubkey_bytes = skp.public().to_arr(); let mut input = Vec::new(); @@ -144,7 +145,7 @@ fn registration_response_roundtrip() { #[test] fn registration_upload_roundtrip() { let mut rng = OsRng; - let skp = KeyPair::<::Group>::generate_random(&mut rng); + let skp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let pubkey_bytes = skp.public().to_arr(); let mut key = [0u8; 32]; @@ -176,7 +177,7 @@ fn credential_request_roundtrip() { let alpha = random_ristretto_point(); let alpha_bytes = alpha.to_arr().to_vec(); - let client_e_kp = KeyPair::<::Group>::generate_random(&mut rng); + let client_e_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let mut client_nonce = vec![0u8; NonceLen::to_usize()]; rng.fill_bytes(&mut client_nonce); @@ -219,7 +220,7 @@ fn credential_response_roundtrip() { ]; rng.fill_bytes(&mut masked_response); - let server_e_kp = KeyPair::<::Group>::generate_random(&mut rng); + let server_e_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let mut mac = [0u8; MAC_SIZE]; rng.fill_bytes(&mut mac); let mut server_nonce = vec![0u8; NonceLen::to_usize()]; @@ -274,7 +275,7 @@ fn client_login_roundtrip() { let mut rng = OsRng; let sc = ::random_nonzero_scalar(&mut rng); - let client_e_kp = KeyPair::<::Group>::generate_random(&mut rng); + let client_e_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let mut client_nonce = vec![0u8; NonceLen::to_usize()]; rng.fill_bytes(&mut client_nonce); @@ -298,7 +299,7 @@ fn client_login_roundtrip() { fn ke1_message_roundtrip() { let mut rng = OsRng; - let client_e_kp = KeyPair::<::Group>::generate_random(&mut rng); + let client_e_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let mut client_nonce = vec![0u8; NonceLen::to_usize()]; rng.fill_bytes(&mut client_nonce); @@ -315,7 +316,7 @@ fn ke1_message_roundtrip() { fn ke2_message_roundtrip() { let mut rng = OsRng; - let server_e_kp = KeyPair::<::Group>::generate_random(&mut rng); + let server_e_kp = KeyPair::<::OprfGroup>::generate_random(&mut rng); let mut mac = [0u8; MAC_SIZE]; rng.fill_bytes(&mut mac); let mut server_nonce = vec![0u8; NonceLen::to_usize()]; diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs index a79f089..7480e8f 100644 --- a/src/tests/full_test.rs +++ b/src/tests/full_test.rs @@ -29,7 +29,8 @@ use zeroize::Zeroize; struct RistrettoSha5123dhNoSlowHash; impl CipherSuite for RistrettoSha5123dhNoSlowHash { - type Group = RistrettoPoint; + type OprfGroup = RistrettoPoint; + type KeGroup = RistrettoPoint; type KeyExchange = TripleDH; type Hash = sha2::Sha512; type SlowHash = NoOpHash; @@ -280,11 +281,11 @@ fn generate_parameters() -> TestVectorParameters { let mut rng = OsRng; // Inputs - let server_s_kp = KeyPair::::generate_random(&mut rng); - let server_e_kp = KeyPair::::generate_random(&mut rng); - let client_s_kp = KeyPair::::generate_random(&mut rng); - let client_e_kp = KeyPair::::generate_random(&mut rng); - let fake_kp = KeyPair::::generate_random(&mut rng); + let server_s_kp = KeyPair::::generate_random(&mut rng); + let server_e_kp = KeyPair::::generate_random(&mut rng); + let client_s_kp = KeyPair::::generate_random(&mut rng); + let client_e_kp = KeyPair::::generate_random(&mut rng); + let fake_kp = KeyPair::::generate_random(&mut rng); let credential_identifier = b"credIdentifier"; let id_u = b"idU"; let id_s = b"idS"; @@ -307,14 +308,14 @@ fn generate_parameters() -> TestVectorParameters { ) .unwrap(); - let blinding_factor = CS::Group::random_nonzero_scalar(&mut rng); - let blinding_factor_bytes = CS::Group::scalar_as_bytes(blinding_factor); + let blinding_factor = CS::OprfGroup::random_nonzero_scalar(&mut rng); + let blinding_factor_bytes = CS::OprfGroup::scalar_as_bytes(blinding_factor); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec()); let client_registration_start_result = ClientRegistration::::start(&mut blinding_factor_registration_rng, password).unwrap(); let blinding_factor_bytes_returned = - CS::Group::scalar_as_bytes(client_registration_start_result.state.token.blind); + CS::OprfGroup::scalar_as_bytes(client_registration_start_result.state.token.blind); assert_eq!( hex::encode(&blinding_factor_bytes), hex::encode(&blinding_factor_bytes_returned) diff --git a/src/tests/opaque_test_vectors.rs b/src/tests/opaque_test_vectors.rs index 776f631..9be3e16 100644 --- a/src/tests/opaque_test_vectors.rs +++ b/src/tests/opaque_test_vectors.rs @@ -17,7 +17,8 @@ use serde_json::Value; struct Ristretto255Sha512NoSlowHash; impl CipherSuite for Ristretto255Sha512NoSlowHash { - type Group = RistrettoPoint; + type OprfGroup = RistrettoPoint; + type KeGroup = RistrettoPoint; type KeyExchange = TripleDH; type Hash = sha2::Sha512; type SlowHash = NoOpHash; @@ -27,7 +28,8 @@ impl CipherSuite for Ristretto255Sha512NoSlowHash { struct P256Sha256NoSlowHash; #[cfg(feature = "p256")] impl CipherSuite for P256Sha256NoSlowHash { - type Group = p256_::ProjectivePoint; + type OprfGroup = p256_::ProjectivePoint; + type KeGroup = p256_::ProjectivePoint; type KeyExchange = TripleDH; type Hash = sha2::Sha256; type SlowHash = NoOpHash; @@ -750,7 +752,7 @@ fn populate_test_vectors(values: &Value) -> TestVectorParameter dummy_private_key: parse_default!( values, "client_private_key", - vec![0u8; as SizedBytes>::Len::to_usize()] + vec![0u8; as SizedBytes>::Len::to_usize()] ), dummy_masking_key: parse_default!(values, "masking_key", vec![0u8; 64]), context: parse!(values, "Context"),