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"
This commit is contained in:
daxpedda
2021-08-04 12:24:46 -07:00
committed by GitHub
parent 10a38bc58b
commit 88673d8e05
14 changed files with 377 additions and 157 deletions
+2 -1
View File
@@ -44,7 +44,8 @@ use opaque_ke::{
#[allow(dead_code)] #[allow(dead_code)]
struct Default; struct Default;
impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = opaque_ke::slow_hash::NoOpHash; type SlowHash = opaque_ke::slow_hash::NoOpHash;
+2 -1
View File
@@ -37,7 +37,8 @@ use opaque_ke::{
#[allow(dead_code)] #[allow(dead_code)]
struct Default; struct Default;
impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = opaque_ke::slow_hash::NoOpHash; type SlowHash = opaque_ke::slow_hash::NoOpHash;
+6 -3
View File
@@ -8,9 +8,10 @@
use crate::{group::Group, hash::Hash, key_exchange::traits::KeyExchange, slow_hash::SlowHash}; use crate::{group::Group, hash::Hash, key_exchange::traits::KeyExchange, slow_hash::SlowHash};
/// Configures the underlying primitives used in OPAQUE /// 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 /// with an extension trait PasswordToCurve that allows some customization on
/// how to hash a password to a curve point. See `group::Group`. /// 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 /// * `KeyExchange`: The key exchange protocol to use in the login step
/// * `Hash`: The main hashing function to use /// * `Hash`: The main hashing function to use
/// * `SlowHash`: A slow hashing function, typically used for password hashing /// * `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 /// A finite cyclic group along with a point representation along with
/// an extension trait PasswordToCurve that allows some customization on /// an extension trait PasswordToCurve that allows some customization on
/// how to hash a password to a curve point. See `group::Group`. /// 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 /// A key exchange protocol
type KeyExchange: KeyExchange<Self::Hash, Self::Group>; type KeyExchange: KeyExchange<Self::Hash, Self::KeGroup>;
/// The main hash function use (for HKDF computations and hashing transcripts) /// The main hash function use (for HKDF computations and hashing transcripts)
type Hash: Hash; type Hash: Hash;
/// A slow hashing function, typically used for password hashing /// A slow hashing function, typically used for password hashing
+19 -15
View File
@@ -31,15 +31,17 @@ const NONCE_LEN: usize = 32;
fn build_inner_envelope_internal<CS: CipherSuite>( fn build_inner_envelope_internal<CS: CipherSuite>(
random_pwd: &[u8], random_pwd: &[u8],
nonce: &[u8], nonce: &[u8],
) -> Result<PublicKey<CS::Group>, ProtocolError> { ) -> Result<PublicKey<CS::KeGroup>, ProtocolError> {
let h = Hkdf::<CS::Hash>::new(None, random_pwd); let h = Hkdf::<CS::Hash>::new(None, random_pwd);
let mut keypair_seed = vec![0u8; <PrivateKey<CS::Group> as SizedBytes>::Len::to_usize()]; let mut keypair_seed = vec![0u8; <PrivateKey<CS::KeGroup> as SizedBytes>::Len::to_usize()];
h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed) h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed)
.map_err(|_| InternalPakeError::HkdfError)?; .map_err(|_| InternalPakeError::HkdfError)?;
let client_static_keypair = let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
KeyPair::<CS::Group>::from_private_key_slice(&CS::Group::scalar_as_bytes( &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash>(
CS::Group::hash_to_scalar::<CS::Hash>(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?, &keypair_seed[..],
))?; STR_OPAQUE_HASH_TO_SCALAR,
)?),
)?;
Ok(client_static_keypair.public().clone()) Ok(client_static_keypair.public().clone())
} }
@@ -47,15 +49,17 @@ fn build_inner_envelope_internal<CS: CipherSuite>(
fn recover_keys_internal<CS: CipherSuite>( fn recover_keys_internal<CS: CipherSuite>(
random_pwd: &[u8], random_pwd: &[u8],
nonce: &[u8], nonce: &[u8],
) -> Result<KeyPair<CS::Group>, ProtocolError> { ) -> Result<KeyPair<CS::KeGroup>, ProtocolError> {
let h = Hkdf::<CS::Hash>::new(None, random_pwd); let h = Hkdf::<CS::Hash>::new(None, random_pwd);
let mut keypair_seed = vec![0u8; <PrivateKey<CS::Group> as SizedBytes>::Len::to_usize()]; let mut keypair_seed = vec![0u8; <PrivateKey<CS::KeGroup> as SizedBytes>::Len::to_usize()];
h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed) h.expand(&[nonce, STR_PRIVATE_KEY].concat(), &mut keypair_seed)
.map_err(|_| InternalPakeError::HkdfError)?; .map_err(|_| InternalPakeError::HkdfError)?;
let client_static_keypair = let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
KeyPair::<CS::Group>::from_private_key_slice(&CS::Group::scalar_as_bytes( &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash>(
CS::Group::hash_to_scalar::<CS::Hash>(&keypair_seed[..], STR_OPAQUE_HASH_TO_SCALAR)?, &keypair_seed[..],
))?; STR_OPAQUE_HASH_TO_SCALAR,
)?),
)?;
Ok(client_static_keypair) Ok(client_static_keypair)
} }
@@ -110,7 +114,7 @@ impl_debug_eq_hash_for!(struct Envelope<CS: CipherSuite>, [mode, nonce, hmac]);
// key. This key is also used to derive the export_key parameter, which is technically // key. This key is also used to derive the export_key parameter, which is technically
// unrelated to the envelope's encrypted and authenticated contents. // unrelated to the envelope's encrypted and authenticated contents.
pub(crate) struct OpenedEnvelope<CS: CipherSuite> { pub(crate) struct OpenedEnvelope<CS: CipherSuite> {
pub(crate) client_static_keypair: KeyPair<CS::Group>, pub(crate) client_static_keypair: KeyPair<CS::KeGroup>,
pub(crate) export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, pub(crate) export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
pub(crate) id_u: Vec<u8>, pub(crate) id_u: Vec<u8>,
pub(crate) id_s: Vec<u8>, pub(crate) id_s: Vec<u8>,
@@ -134,13 +138,13 @@ type SealRawResult<CS> = (
#[cfg(not(test))] #[cfg(not(test))]
type SealResult<CS> = ( type SealResult<CS> = (
Envelope<CS>, Envelope<CS>,
PublicKey<<CS as CipherSuite>::Group>, PublicKey<<CS as CipherSuite>::KeGroup>,
GenericArray<u8, <<CS as CipherSuite>::Hash as Digest>::OutputSize>, GenericArray<u8, <<CS as CipherSuite>::Hash as Digest>::OutputSize>,
); );
#[cfg(test)] #[cfg(test)]
type SealResult<CS> = ( type SealResult<CS> = (
Envelope<CS>, Envelope<CS>,
PublicKey<<CS as CipherSuite>::Group>, PublicKey<<CS as CipherSuite>::KeGroup>,
GenericArray<u8, <<CS as CipherSuite>::Hash as Digest>::OutputSize>, GenericArray<u8, <<CS as CipherSuite>::Hash as Digest>::OutputSize>,
Vec<u8>, Vec<u8>,
); );
+1
View File
@@ -10,6 +10,7 @@ mod expand;
#[cfg(feature = "p256")] #[cfg(feature = "p256")]
pub(crate) mod p256; pub(crate) mod p256;
mod ristretto; mod ristretto;
mod x25519;
use crate::errors::{InternalPakeError, ProtocolError}; use crate::errors::{InternalPakeError, ProtocolError};
use crate::hash::Hash; use crate::hash::Hash;
+182
View File
@@ -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<H: Hash>(_msg: &[u8], _dst: &[u8]) -> Result<Self, ProtocolError> {
unreachable!("this algorithm should only be used as the `KeGroup`")
}
fn hash_to_scalar<H: Hash>(_input: &[u8], _dst: &[u8]) -> Result<Self::Scalar, ProtocolError> {
unreachable!("this algorithm should only be used as the `KeGroup`")
}
type Scalar = Scalar;
type ScalarLen = U32;
fn from_scalar_slice(
scalar_bits: &GenericArray<u8, Self::ScalarLen>,
) -> Result<Self::Scalar, InternalPakeError> {
Ok(Scalar::from_bytes_mod_order(*scalar_bits.as_ref()))
}
fn random_nonzero_scalar<R: RngCore + CryptoRng>(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<u8, Self::ScalarLen> {
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<u8, Self::ElemLen>,
) -> Result<Self, InternalPakeError> {
Ok(Self(*element_bits.as_ref()))
}
// serialization of a group element
fn to_arr(&self) -> GenericArray<u8, Self::ElemLen> {
self.to_bytes().into()
}
fn base_point() -> Self {
X25519_BASEPOINT
}
fn mult_by_slice(&self, scalar: &GenericArray<u8, Self::ScalarLen>) -> 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::<X25519Sha512NoSlowHash>::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(())
}
+1 -1
View File
@@ -411,7 +411,7 @@ impl<G: Group, HashLen: ArrayLength<u8>> FromBytes for Ke2Message<G, HashLen> {
)?; )?;
// Check the public key bytes // Check the public key bytes
let server_e_pk = KeyPair::<CS::Group>::check_public_key(PublicKey::from_bytes( let server_e_pk = KeyPair::<CS::OprfGroup>::check_public_key(PublicKey::from_bytes(
&unchecked_server_e_pk[..key_len], &unchecked_server_e_pk[..key_len],
)?)?; )?)?;
+2 -1
View File
@@ -462,7 +462,8 @@ mod tests {
struct Default; struct Default;
impl CipherSuite for Default { impl CipherSuite for Default {
type Group = RistrettoPoint; type OprfGroup = RistrettoPoint;
type KeGroup = RistrettoPoint;
type KeyExchange = crate::key_exchange::tripledh::TripleDH; type KeyExchange = crate::key_exchange::tripledh::TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = crate::slow_hash::NoOpHash; type SlowHash = crate::slow_hash::NoOpHash;
+35 -17
View File
@@ -16,7 +16,9 @@
//! //!
//! OPAQUE is a protocol between a client and a server. They must first agree on a collection of primitives //! 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: //! 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 key exchange protocol,
//! * a hashing function, and //! * a hashing function, and
//! * a slow hashing function. //! * a slow hashing function.
@@ -26,7 +28,8 @@
//! use opaque_ke::CipherSuite; //! use opaque_ke::CipherSuite;
//! struct Default; //! struct Default;
//! impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! type Hash = sha2::Sha512; //! type Hash = sha2::Sha512;
//! type SlowHash = opaque_ke::slow_hash::NoOpHash; //! type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -47,7 +50,8 @@
//! # use opaque_ke::ServerSetup; //! # use opaque_ke::ServerSetup;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -79,7 +83,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -109,7 +114,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -146,7 +152,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -184,7 +191,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -226,7 +234,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -259,7 +268,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -312,7 +322,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -357,7 +368,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -432,7 +444,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -509,7 +522,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -574,7 +588,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -611,7 +626,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -660,7 +676,8 @@
//! # use opaque_ke::CipherSuite; //! # use opaque_ke::CipherSuite;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
@@ -737,7 +754,8 @@
//! # use zeroize::Zeroize; //! # use zeroize::Zeroize;
//! # struct Default; //! # struct Default;
//! # impl CipherSuite for 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 KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
//! # type Hash = sha2::Sha512; //! # type Hash = sha2::Sha512;
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
+38 -38
View File
@@ -28,13 +28,13 @@ use rand::{CryptoRng, RngCore};
/// The message sent by the client to the server, to initiate registration /// The message sent by the client to the server, to initiate registration
pub struct RegistrationRequest<CS: CipherSuite> { pub struct RegistrationRequest<CS: CipherSuite> {
/// blinded password information /// blinded password information
pub(crate) alpha: CS::Group, pub(crate) alpha: CS::OprfGroup,
} }
impl<CS: CipherSuite> RegistrationRequest<CS> { impl<CS: CipherSuite> RegistrationRequest<CS> {
/// Only used for testing purposes /// Only used for testing purposes
#[cfg(test)] #[cfg(test)]
pub fn get_alpha_for_testing(&self) -> CS::Group { pub fn get_alpha_for_testing(&self) -> CS::OprfGroup {
self.alpha self.alpha
} }
} }
@@ -46,7 +46,7 @@ impl<CS: CipherSuite> Clone for RegistrationRequest<CS> {
} }
} }
impl_debug_eq_hash_for!(struct RegistrationRequest<CS: CipherSuite>, [alpha], [CS::Group]); impl_debug_eq_hash_for!(struct RegistrationRequest<CS: CipherSuite>, [alpha], [CS::OprfGroup]);
impl<CS: CipherSuite> RegistrationRequest<CS> { impl<CS: CipherSuite> RegistrationRequest<CS> {
/// Serialization into bytes /// Serialization into bytes
@@ -56,12 +56,12 @@ impl<CS: CipherSuite> RegistrationRequest<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::OprfGroup as Group>::ElemLen::to_usize();
let checked_slice = check_slice_size(input, elem_len, "first_message_bytes")?; let checked_slice = check_slice_size(input, elem_len, "first_message_bytes")?;
// Check that the message is actually containing an element of the // Check that the message is actually containing an element of the
// correct subgroup // correct subgroup
let arr = GenericArray::from_slice(checked_slice); 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 // Throw an error if the identity group element is encountered
if alpha.is_identity() { if alpha.is_identity() {
@@ -77,9 +77,9 @@ impl_serialize_and_deserialize_for!(RegistrationRequest);
/// registration attempt /// registration attempt
pub struct RegistrationResponse<CS: CipherSuite> { pub struct RegistrationResponse<CS: CipherSuite> {
/// The server's oprf output /// The server's oprf output
pub(crate) beta: CS::Group, pub(crate) beta: CS::OprfGroup,
/// Server's static public key /// Server's static public key
pub(crate) server_s_pk: PublicKey<CS::Group>, pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
} }
// Cannot be derived because it would require for CS to be Clone. // Cannot be derived because it would require for CS to be Clone.
@@ -95,7 +95,7 @@ impl<CS: CipherSuite> Clone for RegistrationResponse<CS> {
impl_debug_eq_hash_for!( impl_debug_eq_hash_for!(
struct RegistrationResponse<CS: CipherSuite>, struct RegistrationResponse<CS: CipherSuite>,
[beta, server_s_pk], [beta, server_s_pk],
[CS::Group], [CS::OprfGroup],
); );
impl<CS: CipherSuite> RegistrationResponse<CS> { impl<CS: CipherSuite> RegistrationResponse<CS> {
@@ -106,15 +106,15 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::OprfGroup as Group>::ElemLen::to_usize();
let key_len = <PublicKey<CS::Group> as SizedBytes>::Len::to_usize(); let key_len = <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize();
let checked_slice = let checked_slice =
check_slice_size(input, elem_len + key_len, "registration_response_bytes")?; check_slice_size(input, elem_len + key_len, "registration_response_bytes")?;
// Check that the message is actually containing an element of the // Check that the message is actually containing an element of the
// correct subgroup // correct subgroup
let arr = GenericArray::from_slice(&checked_slice[..elem_len]); 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 // Throw an error if the identity group element is encountered
if beta.is_identity() { if beta.is_identity() {
@@ -122,7 +122,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
} }
// Ensure that public key is valid // Ensure that public key is valid
let server_s_pk = KeyPair::<CS::Group>::check_public_key(PublicKey::from_bytes( let server_s_pk = KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
&checked_slice[elem_len..], &checked_slice[elem_len..],
)?)?; )?)?;
@@ -132,7 +132,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
#[cfg(test)] #[cfg(test)]
/// Only used for tests, where we can set the beta value to test for the reflection /// Only used for tests, where we can set the beta value to test for the reflection
/// error case /// 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 { Self {
beta: new_beta, beta: new_beta,
server_s_pk: self.server_s_pk.clone(), server_s_pk: self.server_s_pk.clone(),
@@ -151,7 +151,7 @@ pub struct RegistrationUpload<CS: CipherSuite> {
/// The masking key used to mask the envelope /// The masking key used to mask the envelope
pub(crate) masking_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, pub(crate) masking_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
/// The user's public key /// The user's public key
pub(crate) client_s_pk: PublicKey<CS::Group>, pub(crate) client_s_pk: PublicKey<CS::KeGroup>,
} }
impl_clone_for!( impl_clone_for!(
@@ -176,7 +176,7 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let key_len = <PublicKey<CS::Group> as SizedBytes>::Len::to_usize(); let key_len = <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize();
let hash_len = <CS::Hash as Digest>::OutputSize::to_usize(); let hash_len = <CS::Hash as Digest>::OutputSize::to_usize();
let checked_slice = let checked_slice =
check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?; check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?;
@@ -186,14 +186,14 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
masking_key: GenericArray::clone_from_slice( masking_key: GenericArray::clone_from_slice(
&checked_slice[key_len..key_len + hash_len], &checked_slice[key_len..key_len + hash_len],
), ),
client_s_pk: KeyPair::<CS::Group>::check_public_key(PublicKey::from_bytes( client_s_pk: KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
&checked_slice[..key_len], &checked_slice[..key_len],
)?)?, )?)?,
}) })
} }
// Creates a dummy instance used for faking a [CredentialResponse] // Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, S: SecretKey<CS::Group>>( pub(crate) fn dummy<R: RngCore + CryptoRng, S: SecretKey<CS::KeGroup>>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, S>, server_setup: &ServerSetup<CS, S>,
) -> Self { ) -> Self {
@@ -213,8 +213,8 @@ impl_serialize_and_deserialize_for!(RegistrationUpload);
/// The message sent by the user to the server, to initiate registration /// The message sent by the user to the server, to initiate registration
pub struct CredentialRequest<CS: CipherSuite> { pub struct CredentialRequest<CS: CipherSuite> {
/// blinded password information /// blinded password information
pub(crate) alpha: CS::Group, pub(crate) alpha: CS::OprfGroup,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1Message, pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
} }
// Cannot be derived because it would require for CS to be Clone. // Cannot be derived because it would require for CS to be Clone.
@@ -231,8 +231,8 @@ impl_debug_eq_hash_for!(
struct CredentialRequest<CS: CipherSuite>, struct CredentialRequest<CS: CipherSuite>,
[alpha, ke1_message], [alpha, ke1_message],
[ [
CS::Group, CS::OprfGroup,
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1Message <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message
], ],
); );
@@ -244,14 +244,14 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::OprfGroup as Group>::ElemLen::to_usize();
let checked_slice = check_slice_size_atleast(input, elem_len, "login_first_message_bytes")?; 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 // Check that the message is actually containing an element of the
// correct subgroup // correct subgroup
let arr = GenericArray::from_slice(&checked_slice[..elem_len]); 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 // Throw an error if the identity group element is encountered
if alpha.is_identity() { if alpha.is_identity() {
@@ -259,7 +259,7 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
} }
let ke1_message = let ke1_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1Message::from_bytes::<CS>( <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes::<CS>(
&checked_slice[elem_len..], &checked_slice[elem_len..],
)?; )?;
@@ -268,7 +268,7 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
/// Only used for testing purposes /// Only used for testing purposes
#[cfg(test)] #[cfg(test)]
pub fn get_alpha_for_testing(&self) -> CS::Group { pub fn get_alpha_for_testing(&self) -> CS::OprfGroup {
self.alpha self.alpha
} }
} }
@@ -279,10 +279,10 @@ impl_serialize_and_deserialize_for!(CredentialRequest);
/// login attempt /// login attempt
pub struct CredentialResponse<CS: CipherSuite> { pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output /// the server's oprf output
pub(crate) beta: CS::Group, pub(crate) beta: CS::OprfGroup,
pub(crate) masking_nonce: Vec<u8>, pub(crate) masking_nonce: Vec<u8>,
pub(crate) masked_response: Vec<u8>, pub(crate) masked_response: Vec<u8>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2Message, pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
} }
// Cannot be derived because it would require for CS to be Clone. // Cannot be derived because it would require for CS to be Clone.
@@ -301,8 +301,8 @@ impl_debug_eq_hash_for!(
struct CredentialResponse<CS: CipherSuite>, struct CredentialResponse<CS: CipherSuite>,
[beta, masking_nonce, masked_response, ke2_message], [beta, masking_nonce, masked_response, ke2_message],
[ [
CS::Group, CS::OprfGroup,
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2Message, <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
], ],
); );
@@ -317,7 +317,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
} }
pub(crate) fn serialize_without_ke( pub(crate) fn serialize_without_ke(
beta: &CS::Group, beta: &CS::OprfGroup,
masking_nonce: &[u8], masking_nonce: &[u8],
masked_response: &[u8], masked_response: &[u8],
) -> Vec<u8> { ) -> Vec<u8> {
@@ -326,8 +326,8 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::OprfGroup as Group>::ElemLen::to_usize();
let key_len = <PublicKey<CS::Group> as SizedBytes>::Len::to_usize(); let key_len = <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize();
let nonce_len: usize = 32; let nonce_len: usize = 32;
let envelope_len = Envelope::<CS>::len(); let envelope_len = Envelope::<CS>::len();
let masked_response_len = key_len + envelope_len; let masked_response_len = key_len + envelope_len;
@@ -343,7 +343,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
// correct subgroup // correct subgroup
let beta_bytes = &checked_slice[..elem_len]; let beta_bytes = &checked_slice[..elem_len];
let arr = GenericArray::from_slice(beta_bytes); 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 // Throw an error if the identity group element is encountered
if beta.is_identity() { if beta.is_identity() {
@@ -355,7 +355,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
[elem_len + nonce_len..elem_len + nonce_len + masked_response_len] [elem_len + nonce_len..elem_len + nonce_len + masked_response_len]
.to_vec(); .to_vec();
let ke2_message = let ke2_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2Message::from_bytes::<CS>( <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message::from_bytes::<CS>(
&checked_slice[elem_len + nonce_len + masked_response_len..], &checked_slice[elem_len + nonce_len + masked_response_len..],
)?; )?;
@@ -370,7 +370,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
#[cfg(test)] #[cfg(test)]
/// Only used for tests, where we can set the beta value to test for the reflection /// Only used for tests, where we can set the beta value to test for the reflection
/// error case /// 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 { Self {
beta: new_beta, beta: new_beta,
masking_nonce: self.masking_nonce.clone(), 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 /// The answer sent by the client to the server, upon reception of the
/// sealed envelope /// sealed envelope
pub struct CredentialFinalization<CS: CipherSuite> { pub struct CredentialFinalization<CS: CipherSuite> {
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE3Message, pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message,
} }
impl_clone_for!(struct CredentialFinalization<CS: CipherSuite>, [ke3_message]); impl_clone_for!(struct CredentialFinalization<CS: CipherSuite>, [ke3_message]);
impl_debug_eq_hash_for!( impl_debug_eq_hash_for!(
struct CredentialFinalization<CS: CipherSuite>, struct CredentialFinalization<CS: CipherSuite>,
[ke3_message], [ke3_message],
[<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE3Message], [<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message],
); );
impl<CS: CipherSuite> CredentialFinalization<CS> { impl<CS: CipherSuite> CredentialFinalization<CS> {
@@ -404,7 +404,7 @@ impl<CS: CipherSuite> CredentialFinalization<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let ke3_message = let ke3_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE3Message::from_bytes::<CS>( <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message::from_bytes::<CS>(
input, input,
)?; )?;
Ok(Self { ke3_message }) Ok(Self { ke3_message })
+64 -59
View File
@@ -40,32 +40,32 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8] = b"OPAQUE-DeriveKeyPair";
feature = "serialize", feature = "serialize",
derive(serde::Deserialize, serde::Serialize), derive(serde::Deserialize, serde::Serialize),
serde(bound( serde(bound(
deserialize = "KeyPair<CS::Group, S>: serde::Deserialize<'de>", deserialize = "KeyPair<CS::KeGroup, S>: serde::Deserialize<'de>",
serialize = "KeyPair<CS::Group, S>: serde::Serialize" serialize = "KeyPair<CS::KeGroup, S>: serde::Serialize"
)) ))
)] )]
pub struct ServerSetup< pub struct ServerSetup<
CS: CipherSuite, CS: CipherSuite,
S: SecretKey<CS::Group> = PrivateKey<<CS as CipherSuite>::Group>, S: SecretKey<CS::KeGroup> = PrivateKey<<CS as CipherSuite>::KeGroup>,
> { > {
oprf_seed: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, oprf_seed: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
keypair: KeyPair<CS::Group, S>, keypair: KeyPair<CS::KeGroup, S>,
pub(crate) fake_keypair: KeyPair<CS::Group>, pub(crate) fake_keypair: KeyPair<CS::KeGroup>,
} }
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::Group>> { impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<CS::KeGroup>> {
/// Generate a new instance of server setup /// Generate a new instance of server setup
pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self { pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
let keypair = KeyPair::<CS::Group>::generate_random(rng); let keypair = KeyPair::<CS::KeGroup>::generate_random(rng);
Self::new_with_key(rng, keypair) Self::new_with_key(rng, keypair)
} }
} }
impl<CS: CipherSuite, S: SecretKey<CS::Group>> ServerSetup<CS, S> { impl<CS: CipherSuite, S: SecretKey<CS::KeGroup>> ServerSetup<CS, S> {
/// Create [`ServerSetup`] with the given keypair /// Create [`ServerSetup`] with the given keypair
pub fn new_with_key<R: CryptoRng + RngCore>( pub fn new_with_key<R: CryptoRng + RngCore>(
rng: &mut R, rng: &mut R,
keypair: KeyPair<CS::Group, S>, keypair: KeyPair<CS::KeGroup, S>,
) -> Self { ) -> Self {
let mut seed = vec![0u8; <CS::Hash as Digest>::OutputSize::to_usize()]; let mut seed = vec![0u8; <CS::Hash as Digest>::OutputSize::to_usize()];
rng.fill_bytes(&mut seed); rng.fill_bytes(&mut seed);
@@ -73,7 +73,7 @@ impl<CS: CipherSuite, S: SecretKey<CS::Group>> ServerSetup<CS, S> {
Self { Self {
oprf_seed: GenericArray::clone_from_slice(&seed[..]), oprf_seed: GenericArray::clone_from_slice(&seed[..]),
keypair, keypair,
fake_keypair: KeyPair::<CS::Group>::generate_random(rng), fake_keypair: KeyPair::<CS::KeGroup>::generate_random(rng),
} }
} }
@@ -90,7 +90,7 @@ impl<CS: CipherSuite, S: SecretKey<CS::Group>> ServerSetup<CS, S> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> {
let seed_len = <CS::Hash as Digest>::OutputSize::to_usize(); let seed_len = <CS::Hash as Digest>::OutputSize::to_usize();
let key_len = <PrivateKey<CS::Group> as SizedBytes>::Len::to_usize(); let key_len = <PrivateKey<CS::KeGroup> as SizedBytes>::Len::to_usize();
let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")?; let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")?;
Ok(Self { Ok(Self {
@@ -102,7 +102,7 @@ impl<CS: CipherSuite, S: SecretKey<CS::Group>> ServerSetup<CS, S> {
} }
/// Returns the keypair /// Returns the keypair
pub fn keypair(&self) -> &KeyPair<CS::Group, S> { pub fn keypair(&self) -> &KeyPair<CS::KeGroup, S> {
&self.keypair &self.keypair
} }
} }
@@ -122,16 +122,16 @@ impl_debug_eq_hash_for!(
/// The state elements the client holds to register itself /// The state elements the client holds to register itself
pub struct ClientRegistration<CS: CipherSuite> { pub struct ClientRegistration<CS: CipherSuite> {
alpha: CS::Group, alpha: CS::OprfGroup,
/// token containing the client's password and the blinding factor /// token containing the client's password and the blinding factor
pub(crate) token: oprf::Token<CS::Group>, pub(crate) token: oprf::Token<CS::OprfGroup>,
} }
impl_clone_for!(struct ClientRegistration<CS: CipherSuite>, [token, alpha]); impl_clone_for!(struct ClientRegistration<CS: CipherSuite>, [token, alpha]);
impl_debug_eq_hash_for!( impl_debug_eq_hash_for!(
struct ClientRegistration<CS: CipherSuite>, struct ClientRegistration<CS: CipherSuite>,
[token], [token],
[oprf::Token<CS::Group>], [oprf::Token<CS::OprfGroup>],
); );
impl<CS: CipherSuite> ClientRegistration<CS> { impl<CS: CipherSuite> ClientRegistration<CS> {
@@ -139,7 +139,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
[ [
&self.alpha.to_arr().to_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, &self.token.data,
] ]
.concat() .concat()
@@ -147,8 +147,8 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::Group as Group>::ElemLen::to_usize(); let elem_len = <CS::OprfGroup as Group>::ElemLen::to_usize();
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize(); let scalar_len = <CS::OprfGroup as Group>::ScalarLen::to_usize();
let min_expected_len = elem_len + scalar_len; let min_expected_len = elem_len + scalar_len;
let checked_slice = (if input.len() <= min_expected_len { let checked_slice = (if input.len() <= min_expected_len {
Err(InternalPakeError::SizeError { Err(InternalPakeError::SizeError {
@@ -160,14 +160,15 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
Ok(input) Ok(input)
})?; })?;
let alpha = let alpha = CS::OprfGroup::from_element_slice(GenericArray::from_slice(
CS::Group::from_element_slice(GenericArray::from_slice(&checked_slice[..elem_len]))?; &checked_slice[..elem_len],
))?;
// Check that the message is actually containing an element of the // Check that the message is actually containing an element of the
// correct subgroup // correct subgroup
let blinding_factor_bytes = let blinding_factor_bytes =
GenericArray::from_slice(&checked_slice[elem_len..elem_len + scalar_len]); 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(); let password = checked_slice[elem_len + scalar_len..].to_vec();
Ok(Self { Ok(Self {
@@ -257,7 +258,8 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
blinding_factor_rng: &mut R, blinding_factor_rng: &mut R,
password: &[u8], password: &[u8],
) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> { ) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> {
let (token, alpha) = oprf::blind::<R, CS::Group, CS::Hash>(password, blinding_factor_rng)?; let (token, alpha) =
oprf::blind::<R, CS::OprfGroup, CS::Hash>(password, blinding_factor_rng)?;
Ok(ClientRegistrationStartResult { Ok(ClientRegistrationStartResult {
message: RegistrationRequest::<CS> { alpha }, message: RegistrationRequest::<CS> { alpha },
@@ -273,7 +275,7 @@ pub struct ClientRegistrationFinishResult<CS: CipherSuite> {
/// The export key output by client registration /// The export key output by client registration
pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
/// The server's static public key /// The server's static public key
pub server_s_pk: PublicKey<CS::Group>, pub server_s_pk: PublicKey<CS::KeGroup>,
/// Instance of the ClientRegistration, only used in tests for checking zeroize /// Instance of the ClientRegistration, only used in tests for checking zeroize
#[cfg(test)] #[cfg(test)]
pub state: ClientRegistration<CS>, pub state: ClientRegistration<CS>,
@@ -321,8 +323,10 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
return Err(ProtocolError::ReflectedValueError); return Err(ProtocolError::ReflectedValueError);
} }
let password_derived_key = let password_derived_key = get_password_derived_key::<CS::OprfGroup, CS::SlowHash, CS::Hash>(
get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>(&self.token, r2.beta)?; &self.token,
r2.beta,
)?;
#[cfg_attr(not(test), allow(unused_variables))] #[cfg_attr(not(test), allow(unused_variables))]
let (randomized_pwd, h) = Hkdf::<CS::Hash>::extract(None, &password_derived_key); let (randomized_pwd, h) = Hkdf::<CS::Hash>::extract(None, &password_derived_key);
@@ -358,7 +362,7 @@ pub struct ServerRegistrationStartResult<CS: CipherSuite> {
pub message: RegistrationResponse<CS>, pub message: RegistrationResponse<CS>,
/// OPRF key, only used in tests /// OPRF key, only used in tests
#[cfg(test)] #[cfg(test)]
pub oprf_key: GenericArray<u8, <CS::Group as Group>::ScalarLen>, pub oprf_key: GenericArray<u8, <CS::OprfGroup as Group>::ScalarLen>,
} }
// Cannot be derived because it would require for CS to be Clone. // Cannot be derived because it would require for CS to be Clone.
@@ -403,18 +407,18 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
/// From the client's "blinded" password, returns a response to be /// From the client's "blinded" password, returns a response to be
/// sent back to the client, as well as a ServerRegistration /// sent back to the client, as well as a ServerRegistration
pub fn start<S: SecretKey<CS::Group>>( pub fn start<S: SecretKey<CS::KeGroup>>(
server_setup: &ServerSetup<CS, S>, server_setup: &ServerSetup<CS, S>,
message: RegistrationRequest<CS>, message: RegistrationRequest<CS>,
credential_identifier: &[u8], credential_identifier: &[u8],
) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> { ) -> Result<ServerRegistrationStartResult<CS>, ProtocolError> {
let oprf_key = oprf_key_from_seed::<CS::Group, CS::Hash>( let oprf_key = oprf_key_from_seed::<CS::OprfGroup, CS::Hash>(
&server_setup.oprf_seed, &server_setup.oprf_seed,
credential_identifier, credential_identifier,
)?; )?;
// Compute beta = alpha^oprf_key // Compute beta = alpha^oprf_key
let beta = oprf::evaluate::<CS::Group>(message.alpha, &oprf_key); let beta = oprf::evaluate::<CS::OprfGroup>(message.alpha, &oprf_key);
Ok(ServerRegistrationStartResult { Ok(ServerRegistrationStartResult {
message: RegistrationResponse { message: RegistrationResponse {
@@ -422,7 +426,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
server_s_pk: server_setup.keypair.public().clone(), server_s_pk: server_setup.keypair.public().clone(),
}, },
#[cfg(test)] #[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<CS: CipherSuite> ServerRegistration<CS> {
} }
// Creates a dummy instance used for faking a [CredentialResponse] // Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, S: SecretKey<CS::Group>>( pub(crate) fn dummy<R: RngCore + CryptoRng, S: SecretKey<CS::KeGroup>>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, S>, server_setup: &ServerSetup<CS, S>,
) -> Self { ) -> Self {
@@ -451,14 +455,14 @@ impl_serialize_and_deserialize_for!(ServerRegistration);
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
serde(bound( serde(bound(
deserialize = "oprf::Token<CS::Group>: serde::Deserialize<'de>, <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State: serde::Deserialize<'de>", deserialize = "oprf::Token<CS::OprfGroup>: serde::Deserialize<'de>, <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State: serde::Deserialize<'de>",
serialize = "oprf::Token<CS::Group>: serde::Serialize, <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State: serde::Serialize" serialize = "oprf::Token<CS::OprfGroup>: serde::Serialize, <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State: serde::Serialize"
)) ))
)] )]
pub struct ClientLogin<CS: CipherSuite> { pub struct ClientLogin<CS: CipherSuite> {
/// token containing the client's password and the blinding factor /// token containing the client's password and the blinding factor
token: oprf::Token<CS::Group>, token: oprf::Token<CS::OprfGroup>,
ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State, ke1_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State,
serialized_credential_request: Vec<u8>, serialized_credential_request: Vec<u8>,
} }
@@ -466,14 +470,14 @@ impl_clone_for!(struct ClientLogin<CS: CipherSuite>, [token, ke1_state, serializ
impl_debug_eq_hash_for!( impl_debug_eq_hash_for!(
struct ClientLogin<CS: CipherSuite>, struct ClientLogin<CS: CipherSuite>,
[token, ke1_state, serialized_credential_request], [token, ke1_state, serialized_credential_request],
[oprf::Token<CS::Group>, <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State], [oprf::Token<CS::OprfGroup>, <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State],
); );
impl<CS: CipherSuite> ClientLogin<CS> { impl<CS: CipherSuite> ClientLogin<CS> {
/// Serialization into bytes /// Serialization into bytes
pub fn serialize(&self) -> Result<Vec<u8>, ProtocolError> { pub fn serialize(&self) -> Result<Vec<u8>, ProtocolError> {
let output: Vec<u8> = [ let output: Vec<u8> = [
&CS::Group::scalar_as_bytes(self.token.blind)[..], &CS::OprfGroup::scalar_as_bytes(self.token.blind)[..],
&serialize(&self.serialized_credential_request, 2)?, &serialize(&self.serialized_credential_request, 2)?,
&serialize(&self.ke1_state.to_bytes(), 2)?, &serialize(&self.ke1_state.to_bytes(), 2)?,
&self.token.data, &self.token.data,
@@ -484,7 +488,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize(); let scalar_len = <CS::OprfGroup as Group>::ScalarLen::to_usize();
let checked_slice = (if input.len() <= scalar_len { let checked_slice = (if input.len() <= scalar_len {
Err(InternalPakeError::SizeError { Err(InternalPakeError::SizeError {
name: "client_login_bytes", name: "client_login_bytes",
@@ -496,13 +500,13 @@ impl<CS: CipherSuite> ClientLogin<CS> {
})?; })?;
let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[..scalar_len]); 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 (serialized_credential_request, remainder) = tokenize(&checked_slice[scalar_len..], 2)?;
let (ke1_state_bytes, password) = tokenize(&remainder, 2)?; let (ke1_state_bytes, password) = tokenize(&remainder, 2)?;
let ke1_state = let ke1_state =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE1State::from_bytes::<CS>( <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State::from_bytes::<CS>(
&ke1_state_bytes[..], &ke1_state_bytes[..],
)?; )?;
Ok(Self { Ok(Self {
@@ -575,7 +579,7 @@ pub struct ClientLoginFinishResult<CS: CipherSuite> {
/// The client-side export key /// The client-side export key
pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, pub export_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
/// The server's static public key /// The server's static public key
pub server_s_pk: PublicKey<CS::Group>, pub server_s_pk: PublicKey<CS::KeGroup>,
/// Instance of the ClientLogin, only used in tests for checking zeroize /// Instance of the ClientLogin, only used in tests for checking zeroize
#[cfg(test)] #[cfg(test)]
pub state: ClientLogin<CS>, pub state: ClientLogin<CS>,
@@ -611,7 +615,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
rng: &mut R, rng: &mut R,
password: &[u8], password: &[u8],
) -> Result<ClientLoginStartResult<CS>, ProtocolError> { ) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
let (token, alpha) = oprf::blind::<R, CS::Group, CS::Hash>(password, rng)?; let (token, alpha) = oprf::blind::<R, CS::OprfGroup, CS::Hash>(password, rng)?;
let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(rng)?; let (ke1_state, ke1_message) = CS::KeyExchange::generate_ke1(rng)?;
@@ -652,7 +656,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
return Err(ProtocolError::ReflectedValueError); return Err(ProtocolError::ReflectedValueError);
} }
let password_derived_key = get_password_derived_key::<CS::Group, CS::SlowHash, CS::Hash>( let password_derived_key = get_password_derived_key::<CS::OprfGroup, CS::SlowHash, CS::Hash>(
&self.token, &self.token,
credential_response.beta, credential_response.beta,
)?; )?;
@@ -722,7 +726,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// The state elements the server holds to record a login /// The state elements the server holds to record a login
pub struct ServerLogin<CS: CipherSuite> { pub struct ServerLogin<CS: CipherSuite> {
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2State, ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State,
_cs: PhantomData<CS>, _cs: PhantomData<CS>,
} }
@@ -730,7 +734,7 @@ impl_clone_for!(struct ServerLogin<CS: CipherSuite>, [ke2_state, _cs]);
impl_debug_eq_hash_for!( impl_debug_eq_hash_for!(
struct ServerLogin<CS: CipherSuite>, struct ServerLogin<CS: CipherSuite>,
[ke2_state, _cs], [ke2_state, _cs],
[<CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2State], [<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State],
); );
/// Optional parameters for server login start /// Optional parameters for server login start
@@ -766,7 +770,7 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
pub server_mac_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>, pub server_mac_key: GenericArray<u8, <CS::Hash as Digest>::OutputSize>,
/// OPRF key, only used in tests /// OPRF key, only used in tests
#[cfg(test)] #[cfg(test)]
pub oprf_key: GenericArray<u8, <CS::Group as Group>::ScalarLen>, pub oprf_key: GenericArray<u8, <CS::OprfGroup as Group>::ScalarLen>,
} }
// Cannot be derived because it would require for CS to be Clone. // Cannot be derived because it would require for CS to be Clone.
@@ -817,15 +821,16 @@ impl<CS: CipherSuite> ServerLogin<CS> {
pub fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(bytes: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
_cs: PhantomData, _cs: PhantomData,
ke2_state: <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::KE2State::from_bytes::< ke2_state:
CS, <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State::from_bytes::<CS>(
>(bytes)?, bytes,
)?,
}) })
} }
/// From the client's "blinded" password, returns a challenge to be /// From the client's "blinded" password, returns a challenge to be
/// sent back to the client, as well as a ServerLogin /// sent back to the client, as well as a ServerLogin
pub fn start<R: RngCore + CryptoRng, S: SecretKey<CS::Group>>( pub fn start<R: RngCore + CryptoRng, S: SecretKey<CS::KeGroup>>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, S>, server_setup: &ServerSetup<CS, S>,
password_file: Option<ServerRegistration<CS>>, password_file: Option<ServerRegistration<CS>>,
@@ -871,7 +876,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let l1_bytes = &l1.serialize(); let l1_bytes = &l1.serialize();
let oprf_key = oprf_key_from_seed::<CS::Group, CS::Hash>( let oprf_key = oprf_key_from_seed::<CS::OprfGroup, CS::Hash>(
&server_setup.oprf_seed, &server_setup.oprf_seed,
credential_identifier, credential_identifier,
) )
@@ -911,7 +916,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
#[cfg(test)] #[cfg(test)]
server_mac_key: result.3, server_mac_key: result.3,
#[cfg(test)] #[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<CS: CipherSuite> ServerLogin<CS> {
self, self,
message: CredentialFinalization<CS>, message: CredentialFinalization<CS>,
) -> Result<ServerLoginFinishResult<CS>, ProtocolError> { ) -> Result<ServerLoginFinishResult<CS>, ProtocolError> {
let session_key = <CS::KeyExchange as KeyExchange<CS::Hash, CS::Group>>::finish_ke( let session_key = <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::finish_ke(
message.ke3_message, message.ke3_message,
&self.ke2_state, &self.ke2_state,
) )
@@ -1033,11 +1038,11 @@ fn oprf_key_from_seed<G: Group, D: Hash>(
fn mask_response<CS: CipherSuite>( fn mask_response<CS: CipherSuite>(
masking_key: &[u8], masking_key: &[u8],
masking_nonce: &[u8], masking_nonce: &[u8],
server_s_pk: &PublicKey<CS::Group>, server_s_pk: &PublicKey<CS::KeGroup>,
envelope: &Envelope<CS>, envelope: &Envelope<CS>,
) -> Result<Vec<u8>, ProtocolError> { ) -> Result<Vec<u8>, ProtocolError> {
let mut xor_pad = let mut xor_pad =
vec![0u8; <PublicKey<CS::Group> as SizedBytes>::Len::to_usize() + Envelope::<CS>::len()]; vec![0u8; <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize() + Envelope::<CS>::len()];
Hkdf::<CS::Hash>::from_prk(masking_key) Hkdf::<CS::Hash>::from_prk(masking_key)
.map_err(|_| InternalPakeError::HkdfError)? .map_err(|_| InternalPakeError::HkdfError)?
.expand( .expand(
@@ -1059,9 +1064,9 @@ fn unmask_response<CS: CipherSuite>(
masking_key: &[u8], masking_key: &[u8],
masking_nonce: &[u8], masking_nonce: &[u8],
masked_response: &[u8], masked_response: &[u8],
) -> Result<(PublicKey<CS::Group>, Envelope<CS>), ProtocolError> { ) -> Result<(PublicKey<CS::KeGroup>, Envelope<CS>), ProtocolError> {
let mut xor_pad = let mut xor_pad =
vec![0u8; <PublicKey<CS::Group> as SizedBytes>::Len::to_usize() + Envelope::<CS>::len()]; vec![0u8; <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize() + Envelope::<CS>::len()];
Hkdf::<CS::Hash>::from_prk(masking_key) Hkdf::<CS::Hash>::from_prk(masking_key)
.map_err(|_| InternalPakeError::HkdfError)? .map_err(|_| InternalPakeError::HkdfError)?
.expand( .expand(
@@ -1074,13 +1079,13 @@ fn unmask_response<CS: CipherSuite>(
.zip(masked_response.iter()) .zip(masked_response.iter())
.map(|(&x1, &x2)| x1 ^ x2) .map(|(&x1, &x2)| x1 ^ x2)
.collect(); .collect();
let key_len = <PublicKey<CS::Group> as SizedBytes>::Len::to_usize(); let key_len = <PublicKey<CS::KeGroup> as SizedBytes>::Len::to_usize();
let unchecked_server_s_pk = let unchecked_server_s_pk =
PublicKey::from_arr(&GenericArray::clone_from_slice(&plaintext[..key_len]))?; PublicKey::from_arr(&GenericArray::clone_from_slice(&plaintext[..key_len]))?;
let envelope = Envelope::deserialize(&plaintext[key_len..])?; let envelope = Envelope::deserialize(&plaintext[key_len..])?;
// Ensure that public key is valid // Ensure that public key is valid
let server_s_pk = KeyPair::<CS::Group>::check_public_key(unchecked_server_s_pk) let server_s_pk = KeyPair::<CS::KeGroup>::check_public_key(unchecked_server_s_pk)
.map_err(|_| ProtocolError::VerificationError(PakeError::SerializationError))?; .map_err(|_| ProtocolError::VerificationError(PakeError::SerializationError))?;
Ok((server_s_pk, envelope)) Ok((server_s_pk, envelope))
+10 -9
View File
@@ -27,7 +27,8 @@ use sha2::Digest;
struct Default; struct Default;
impl CipherSuite for Default { impl CipherSuite for Default {
type Group = RistrettoPoint; type OprfGroup = RistrettoPoint;
type KeGroup = RistrettoPoint;
type KeyExchange = TripleDH; type KeyExchange = TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = crate::slow_hash::NoOpHash; 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(&ciphertext); // ciphertext which is an encrypted private key
mock_envelope_bytes.extend_from_slice(&[0; MAC_SIZE]); // length-MAC_SIZE hmac mock_envelope_bytes.extend_from_slice(&[0; MAC_SIZE]); // length-MAC_SIZE hmac
let mock_client_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let mock_client_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
// serialization order: oprf_key, public key, envelope // serialization order: oprf_key, public key, envelope
let mut bytes = Vec::<u8>::new(); let mut bytes = Vec::<u8>::new();
bytes.extend_from_slice(&mock_client_kp.public().to_arr()); bytes.extend_from_slice(&mock_client_kp.public().to_arr());
@@ -118,7 +119,7 @@ fn registration_response_roundtrip() {
let pt = random_ristretto_point(); let pt = random_ristretto_point();
let beta_bytes = pt.to_arr(); let beta_bytes = pt.to_arr();
let mut rng = OsRng; let mut rng = OsRng;
let skp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let skp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let pubkey_bytes = skp.public().to_arr(); let pubkey_bytes = skp.public().to_arr();
let mut input = Vec::new(); let mut input = Vec::new();
@@ -144,7 +145,7 @@ fn registration_response_roundtrip() {
#[test] #[test]
fn registration_upload_roundtrip() { fn registration_upload_roundtrip() {
let mut rng = OsRng; let mut rng = OsRng;
let skp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let skp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let pubkey_bytes = skp.public().to_arr(); let pubkey_bytes = skp.public().to_arr();
let mut key = [0u8; 32]; let mut key = [0u8; 32];
@@ -176,7 +177,7 @@ fn credential_request_roundtrip() {
let alpha = random_ristretto_point(); let alpha = random_ristretto_point();
let alpha_bytes = alpha.to_arr().to_vec(); let alpha_bytes = alpha.to_arr().to_vec();
let client_e_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let client_e_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::to_usize()]; let mut client_nonce = vec![0u8; NonceLen::to_usize()];
rng.fill_bytes(&mut client_nonce); rng.fill_bytes(&mut client_nonce);
@@ -219,7 +220,7 @@ fn credential_response_roundtrip() {
]; ];
rng.fill_bytes(&mut masked_response); rng.fill_bytes(&mut masked_response);
let server_e_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let server_e_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let mut mac = [0u8; MAC_SIZE]; let mut mac = [0u8; MAC_SIZE];
rng.fill_bytes(&mut mac); rng.fill_bytes(&mut mac);
let mut server_nonce = vec![0u8; NonceLen::to_usize()]; let mut server_nonce = vec![0u8; NonceLen::to_usize()];
@@ -274,7 +275,7 @@ fn client_login_roundtrip() {
let mut rng = OsRng; let mut rng = OsRng;
let sc = <RistrettoPoint as Group>::random_nonzero_scalar(&mut rng); let sc = <RistrettoPoint as Group>::random_nonzero_scalar(&mut rng);
let client_e_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let client_e_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::to_usize()]; let mut client_nonce = vec![0u8; NonceLen::to_usize()];
rng.fill_bytes(&mut client_nonce); rng.fill_bytes(&mut client_nonce);
@@ -298,7 +299,7 @@ fn client_login_roundtrip() {
fn ke1_message_roundtrip() { fn ke1_message_roundtrip() {
let mut rng = OsRng; let mut rng = OsRng;
let client_e_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let client_e_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::to_usize()]; let mut client_nonce = vec![0u8; NonceLen::to_usize()];
rng.fill_bytes(&mut client_nonce); rng.fill_bytes(&mut client_nonce);
@@ -315,7 +316,7 @@ fn ke1_message_roundtrip() {
fn ke2_message_roundtrip() { fn ke2_message_roundtrip() {
let mut rng = OsRng; let mut rng = OsRng;
let server_e_kp = KeyPair::<<Default as CipherSuite>::Group>::generate_random(&mut rng); let server_e_kp = KeyPair::<<Default as CipherSuite>::OprfGroup>::generate_random(&mut rng);
let mut mac = [0u8; MAC_SIZE]; let mut mac = [0u8; MAC_SIZE];
rng.fill_bytes(&mut mac); rng.fill_bytes(&mut mac);
let mut server_nonce = vec![0u8; NonceLen::to_usize()]; let mut server_nonce = vec![0u8; NonceLen::to_usize()];
+10 -9
View File
@@ -29,7 +29,8 @@ use zeroize::Zeroize;
struct RistrettoSha5123dhNoSlowHash; struct RistrettoSha5123dhNoSlowHash;
impl CipherSuite for RistrettoSha5123dhNoSlowHash { impl CipherSuite for RistrettoSha5123dhNoSlowHash {
type Group = RistrettoPoint; type OprfGroup = RistrettoPoint;
type KeGroup = RistrettoPoint;
type KeyExchange = TripleDH; type KeyExchange = TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = NoOpHash; type SlowHash = NoOpHash;
@@ -280,11 +281,11 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
let mut rng = OsRng; let mut rng = OsRng;
// Inputs // Inputs
let server_s_kp = KeyPair::<CS::Group>::generate_random(&mut rng); let server_s_kp = KeyPair::<CS::OprfGroup>::generate_random(&mut rng);
let server_e_kp = KeyPair::<CS::Group>::generate_random(&mut rng); let server_e_kp = KeyPair::<CS::OprfGroup>::generate_random(&mut rng);
let client_s_kp = KeyPair::<CS::Group>::generate_random(&mut rng); let client_s_kp = KeyPair::<CS::OprfGroup>::generate_random(&mut rng);
let client_e_kp = KeyPair::<CS::Group>::generate_random(&mut rng); let client_e_kp = KeyPair::<CS::OprfGroup>::generate_random(&mut rng);
let fake_kp = KeyPair::<CS::Group>::generate_random(&mut rng); let fake_kp = KeyPair::<CS::OprfGroup>::generate_random(&mut rng);
let credential_identifier = b"credIdentifier"; let credential_identifier = b"credIdentifier";
let id_u = b"idU"; let id_u = b"idU";
let id_s = b"idS"; let id_s = b"idS";
@@ -307,14 +308,14 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
) )
.unwrap(); .unwrap();
let blinding_factor = CS::Group::random_nonzero_scalar(&mut rng); let blinding_factor = CS::OprfGroup::random_nonzero_scalar(&mut rng);
let blinding_factor_bytes = CS::Group::scalar_as_bytes(blinding_factor); 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 mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec());
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password).unwrap(); ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password).unwrap();
let blinding_factor_bytes_returned = 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!( assert_eq!(
hex::encode(&blinding_factor_bytes), hex::encode(&blinding_factor_bytes),
hex::encode(&blinding_factor_bytes_returned) hex::encode(&blinding_factor_bytes_returned)
+5 -3
View File
@@ -17,7 +17,8 @@ use serde_json::Value;
struct Ristretto255Sha512NoSlowHash; struct Ristretto255Sha512NoSlowHash;
impl CipherSuite for Ristretto255Sha512NoSlowHash { impl CipherSuite for Ristretto255Sha512NoSlowHash {
type Group = RistrettoPoint; type OprfGroup = RistrettoPoint;
type KeGroup = RistrettoPoint;
type KeyExchange = TripleDH; type KeyExchange = TripleDH;
type Hash = sha2::Sha512; type Hash = sha2::Sha512;
type SlowHash = NoOpHash; type SlowHash = NoOpHash;
@@ -27,7 +28,8 @@ impl CipherSuite for Ristretto255Sha512NoSlowHash {
struct P256Sha256NoSlowHash; struct P256Sha256NoSlowHash;
#[cfg(feature = "p256")] #[cfg(feature = "p256")]
impl CipherSuite for P256Sha256NoSlowHash { impl CipherSuite for P256Sha256NoSlowHash {
type Group = p256_::ProjectivePoint; type OprfGroup = p256_::ProjectivePoint;
type KeGroup = p256_::ProjectivePoint;
type KeyExchange = TripleDH; type KeyExchange = TripleDH;
type Hash = sha2::Sha256; type Hash = sha2::Sha256;
type SlowHash = NoOpHash; type SlowHash = NoOpHash;
@@ -750,7 +752,7 @@ fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> TestVectorParameter
dummy_private_key: parse_default!( dummy_private_key: parse_default!(
values, values,
"client_private_key", "client_private_key",
vec![0u8; <PrivateKey<CS::Group> as SizedBytes>::Len::to_usize()] vec![0u8; <PrivateKey<CS::OprfGroup> as SizedBytes>::Len::to_usize()]
), ),
dummy_masking_key: parse_default!(values, "masking_key", vec![0u8; 64]), dummy_masking_key: parse_default!(values, "masking_key", vec![0u8; 64]),
context: parse!(values, "Context"), context: parse!(values, "Context"),