feat: upgrade crypto ecosystem to latest RustCrypto stack (#1)
Rust CI / cargo audit (push) Successful in 6s
Rust CI / cargo fmt (push) Successful in 4s
Rust CI / test (1.90.0 / no backend / no frontend) (push) Successful in 2m25s
Rust CI / test (stable / no backend / no frontend) (push) Successful in 2m27s
Rust CI / cargo clippy (push) Successful in 1m25s
Rust CI / test (1.90.0 / no backend / --features argon2) (push) Successful in 2m35s
Rust CI / test (stable / no backend / --features argon2) (push) Successful in 2m34s
Rust CI / test (stable / no backend / --features serde) (push) Successful in 2m55s
Rust CI / test (stable / --features curve25519 / no frontend) (push) Successful in 2m31s
Rust CI / test (1.90.0 / no backend / --features serde) (push) Successful in 2m52s
Rust CI / test (1.90.0 / --features curve25519 / no frontend) (push) Successful in 2m29s
Rust CI / test (1.90.0 / --features curve25519 / --features argon2) (push) Successful in 2m37s
Rust CI / test (stable / --features curve25519 / --features argon2) (push) Successful in 2m36s
Rust CI / test (1.90.0 / --features curve25519 / --features serde) (push) Successful in 2m59s
Rust CI / test (stable / --features curve25519 / --features serde) (push) Successful in 3m1s
Rust CI / test (1.90.0 / --features ecdsa / no frontend) (push) Successful in 2m52s
Rust CI / test (stable / --features ecdsa / no frontend) (push) Successful in 2m51s
Rust CI / test (1.90.0 / --features ecdsa / --features argon2) (push) Successful in 2m57s
Rust CI / test (stable / --features ecdsa / --features argon2) (push) Successful in 2m58s
Rust CI / test (1.90.0 / --features ecdsa / --features serde) (push) Successful in 3m19s
Rust CI / test (1.90.0 / --features ristretto255 / no frontend) (push) Successful in 3m2s
Rust CI / test (stable / --features ecdsa / --features serde) (push) Successful in 3m19s
Rust CI / test (1.90.0 / --features ed25519 / no frontend) (push) Successful in 2m53s
Rust CI / test (stable / --features ed25519 / no frontend) (push) Successful in 2m54s
Rust CI / test (1.90.0 / --features ed25519 / --features argon2) (push) Successful in 3m3s
Rust CI / test (stable / --features ed25519 / --features argon2) (push) Successful in 3m0s
Rust CI / test (1.90.0 / --features ed25519 / --features serde) (push) Successful in 3m22s
Rust CI / test (stable / --features ed25519 / --features serde) (push) Successful in 3m22s
Rust CI / test (1.90.0 / --features ristretto255 / --features argon2) (push) Successful in 3m9s
Rust CI / test (stable / --features ristretto255 / no frontend) (push) Successful in 3m4s
Rust CI / test (stable / --features ristretto255 / --features argon2) (push) Successful in 3m11s
Rust CI / test (1.90.0 / --features ristretto255 / --features serde) (push) Successful in 3m28s
Rust CI / test (stable / --features ristretto255 / --features serde) (push) Successful in 3m32s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (push) Successful in 5m26s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (push) Successful in 5m17s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (push) Successful in 5m27s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (push) Successful in 5m43s
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (push) Successful in 5m20s
Rust CI / test (1.90.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (push) Successful in 6m1s
Rust CI / test (stable / --features ristretto255,kem / no frontend) (push) Successful in 4m0s
Rust CI / test (1.90.0 / --features ristretto255,kem / --features argon2) (push) Successful in 4m5s
Rust CI / test (1.90.0 / --features ristretto255,kem / no frontend) (push) Successful in 4m2s
Rust CI / test (stable / --features ristretto255,kem / --features argon2) (push) Successful in 4m3s
Rust CI / test (stable / --features ristretto255,kem / --features serde) (push) Successful in 4m32s
Rust CI / test (1.90.0 / --features ristretto255,kem / --features serde) (push) Successful in 4m31s
Rust CI / test simple_login example (push) Successful in 19s
Rust CI / test digital_locker example (push) Successful in 18s
Rust CI / cargo bench compilation () (push) Successful in 1m47s
Rust CI / cargo bench compilation (--features ristretto255) (push) Successful in 1m55s
Rust CI / cargo bench compilation (--features ristretto255,kem) (push) Successful in 2m35s
Rust CI / no-std (thumbv6m-none-eabi / no backend) (push) Successful in 28s
Rust CI / no-std (wasm32-unknown-unknown / no backend) (push) Successful in 28s
Rust CI / no-std (thumbv6m-none-eabi / curve25519) (push) Successful in 18s
Rust CI / no-std (wasm32-unknown-unknown / curve25519) (push) Successful in 28s
Rust CI / no-std (thumbv6m-none-eabi / ecdsa) (push) Successful in 29s
Rust CI / no-std (wasm32-unknown-unknown / ecdsa) (push) Successful in 28s
Rust CI / no-std (thumbv6m-none-eabi / ed25519) (push) Successful in 29s
Rust CI / no-std (wasm32-unknown-unknown / ed25519) (push) Successful in 30s
Rust CI / no-std (thumbv6m-none-eabi / ristretto255) (push) Successful in 28s
Rust CI / no-std (wasm32-unknown-unknown / ristretto255) (push) Successful in 28s
Rust CI / no-std (thumbv6m-none-eabi / ristretto255,curve25519,ecdsa,ed25519) (push) Successful in 29s
Rust CI / no-std (wasm32-unknown-unknown / ristretto255,curve25519,ecdsa,ed25519) (push) Successful in 19s

Upgrade all core cryptographic dependencies to their latest versions:

Dependencies:
- digest: 0.10 to 0.11
- elliptic-curve: 0.13 to 0.14
- hkdf: 0.12 to 0.13
- hmac: 0.12 to 0.13
- rand: 0.8 to 0.10
- rand_chacha: 0.3 to 0.10
- sha2: 0.10 to 0.11
- getrandom: 0.2 to 0.4 (WASM)
- ml-kem: 0.3.0-rc.0 to 0.3
- ecdsa: 0.16 to 0.17.0-rc.23
- rfc6979: 0.4 to 0.6 (now internal to ecdsa)
- p256/p384/p521: 0.13 to 0.14.0-rc.15
- curve25519-dalek: 4 to 5.0.0-rc
- ed25519-dalek: 2 to 3.0.0-rc
- cryptoki: 0.9 to 0.12
- rustyline: 17 to 18
- scrypt: 0.11 to 0.12
- voprf replaced by voprf-vx 1.0.0-pre.0

Migration changes:
- generic-array 0.14 to 1.4 with hybrid-array 0.4 interop
- ArrayLength<u8> to ArrayLength (generic-array 1.x)
- Added ConcatExt trait to disambiguate from [T]::concat
- Replaced Hmac with SimpleHmac for digest 0.11 compatibility
- Added OutputSize<H>: ArrayLength bounds throughout Hash trait
- Converted hybrid_array::Array between GenericArray at API boundaries
- Updated GroupEncoding Repr bound to hybrid_array::Array
- ECDSA sign now uses ecdsa::hazmat::sign_prehashed_rfc6979
- Removed direct rfc6979 dependency (handled by ecdsa internally)
- Replaced bincode with postcard for no_std serialization
- Re-exported hybrid_array from crate root

Other changes:
- Renamed crate to opaque-vx
- Increased MSRV to 1.89
- Added cryptography to Cargo.toml categories
- Removed Facebook-specific contributions from CONTRIBUTING.md
- Removed v3 to v4 migration test
- Removed unstable rustfmt configurations for stable compatibility

Reviewed-on: #1
Co-authored-by: UneBaguette <[email protected]>
Co-committed-by: UneBaguette <[email protected]>
This commit was merged in pull request #1.
This commit is contained in:
2026-07-01 11:52:12 +02:00
committed by breakingbread
parent 5e2ba86643
commit 71df1ee49a
45 changed files with 1680 additions and 1483 deletions
+10 -8
View File
@@ -11,7 +11,7 @@
use core::ops::Add;
use digest::core_api::{BlockSizeUser, CoreProxy};
use digest::block_api::{CoreProxy, EagerHash, SmallBlockSizeUser};
use generic_array::ArrayLength;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
@@ -30,16 +30,18 @@ use crate::opaque::MaskedResponseLen;
/// * `Ksf`: A key stretching function, typically used for password hashing
pub trait CipherSuite
where
OprfHash<Self>: Hash,
OprfHash<Self>: Hash + EagerHash,
<OprfHash<Self> as CoreProxy>::Core: ProxyHash,
<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
// MaskedResponse: (Nonce + Hash) + KePk
OutputSize<OprfHash<Self>>: Add<NonceLen>,
Sum<OutputSize<OprfHash<Self>>, NonceLen>:
ArrayLength<u8> + Add<<KeGroup<Self> as Group>::PkLen>,
MaskedResponseLen<Self>: ArrayLength<u8>,
OutputSize<OprfHash<Self>>: Add<NonceLen> + ArrayLength,
Sum<OutputSize<OprfHash<Self>>, NonceLen>: ArrayLength + Add<<KeGroup<Self> as Group>::PkLen>,
MaskedResponseLen<Self>: ArrayLength,
// hybrid-array interop bounds
<OprfGroup<Self> as voprf::Group>::ScalarLen: ArrayLength,
<OprfGroup<Self> as voprf::Group>::ElemLen: ArrayLength,
{
/// A VOPRF ciphersuite, see [`voprf::CipherSuite`].
type OprfCs: voprf::CipherSuite;
+24 -22
View File
@@ -11,11 +11,10 @@ use core::convert::TryFrom;
use derive_where::derive_where;
use digest::Output;
use generic_array::GenericArray;
use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, U32};
use hkdf::Hkdf;
use hmac::{Hmac, Mac};
use rand::{CryptoRng, RngCore};
use hkdf::SimpleHkdf as Hkdf;
use hmac::{KeyInit, Mac, SimpleHmac};
use rand::{CryptoRng, Rng};
use zeroize::Zeroize;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfHash};
@@ -108,9 +107,9 @@ pub(crate) type EnvelopeLen<CS: CipherSuite> = Sum<OutputSize<OprfHash<CS>>, Non
impl<CS: CipherSuite> Envelope<CS> {
#[allow(clippy::type_complexity)]
pub(crate) fn seal<R: RngCore + CryptoRng>(
pub(crate) fn seal<R: Rng + CryptoRng>(
rng: &mut R,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
server_s_pk: &PublicKey<KeGroup<CS>>,
ids: Identifiers,
) -> Result<SealResult<CS>, ProtocolError> {
@@ -119,7 +118,7 @@ impl<CS: CipherSuite> Envelope<CS> {
let (mode, client_s_pk) = (
InnerEnvelopeMode::Internal,
build_inner_envelope_internal::<CS>(randomized_pwd_hasher.clone(), nonce)?,
build_inner_envelope_internal::<CS>(randomized_pwd_hasher, nonce)?,
);
let server_s_pk_bytes = server_s_pk.serialize();
@@ -148,7 +147,7 @@ impl<CS: CipherSuite> Envelope<CS> {
/// the aad field. Note that a new nonce is sampled for each call to seal.
#[allow(clippy::type_complexity)]
pub(crate) fn seal_raw<'a>(
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
aad: impl Iterator<Item = &'a [u8]>,
mode: InnerEnvelopeMode,
@@ -163,7 +162,7 @@ impl<CS: CipherSuite> Envelope<CS> {
.expand_multi_info(&[&nonce, &STR_EXPORT_KEY], &mut export_key)
.map_err(|_| InternalError::HkdfError)?;
let mut hmac = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
let mut hmac = SimpleHmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
.map_err(|_| InternalError::HmacError)?;
hmac.update(&nonce);
hmac.update_iter(aad);
@@ -184,7 +183,7 @@ impl<CS: CipherSuite> Envelope<CS> {
pub(crate) fn open<'a>(
&self,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
server_s_pk: PublicKey<KeGroup<CS>>,
optional_ids: Identifiers<'a>,
) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> {
@@ -193,7 +192,7 @@ impl<CS: CipherSuite> Envelope<CS> {
return Err(InternalError::IncompatibleEnvelopeModeError.into());
}
InnerEnvelopeMode::Internal => {
recover_keys_internal::<CS>(randomized_pwd_hasher.clone(), self.nonce)?
recover_keys_internal::<CS>(randomized_pwd_hasher, self.nonce)?
}
};
@@ -222,20 +221,20 @@ impl<CS: CipherSuite> Envelope<CS> {
/// if the key and aad used to construct the envelope are the same.
pub(crate) fn open_raw<'a>(
&self,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
aad: impl Iterator<Item = &'a [u8]>,
) -> Result<OpenedInnerEnvelope<CS>, InternalError> {
let mut hmac_key = Output::<OprfHash<CS>>::default();
let mut export_key = Output::<OprfHash<CS>>::default();
randomized_pwd_hasher
.expand(&self.nonce.concat(STR_AUTH_KEY.into()), &mut hmac_key)
.expand_multi_info(&[&self.nonce, &STR_AUTH_KEY], &mut hmac_key)
.map_err(|_| InternalError::HkdfError)?;
randomized_pwd_hasher
.expand(&self.nonce.concat(STR_EXPORT_KEY.into()), &mut export_key)
.expand_multi_info(&[&self.nonce, &STR_EXPORT_KEY], &mut export_key)
.map_err(|_| InternalError::HkdfError)?;
let mut hmac = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
let mut hmac = SimpleHmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
.map_err(|_| InternalError::HmacError)?;
hmac.update(&self.nonce);
hmac.update_iter(aad);
@@ -250,7 +249,7 @@ impl<CS: CipherSuite> Envelope<CS> {
Self {
mode: InnerEnvelopeMode::Zero,
nonce: GenericArray::default(),
hmac: GenericArray::default(),
hmac: GenericArray::default().into_ha0_4(),
}
}
@@ -262,14 +261,17 @@ impl<CS: CipherSuite> Envelope<CS> {
}
pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>> {
self.nonce.concat_ext(&self.hmac)
self.nonce
.concat_ext(&GenericArray::from_ha0_4(self.hmac.clone()))
}
pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
mode: InnerEnvelopeMode::Internal,
nonce: bytes.take_array("nonce")?,
hmac: bytes.take_array("hmac")?,
hmac: bytes
.take_array::<OutputSize<OprfHash<CS>>>("hmac")?
.into_ha0_4(),
})
}
}
@@ -277,12 +279,12 @@ impl<CS: CipherSuite> Envelope<CS> {
// Helper functions
fn build_inner_envelope_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
) -> Result<PublicKey<KeGroup<CS>>, ProtocolError> {
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.expand_multi_info(&[&nonce, &STR_PRIVATE_KEY], &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
@@ -290,12 +292,12 @@ fn build_inner_envelope_internal<CS: CipherSuite>(
}
fn recover_keys_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
) -> Result<KeyPair<KeGroup<CS>>, ProtocolError> {
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.expand_multi_info(&[&nonce, &STR_PRIVATE_KEY], &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
let client_s_pk = client_s_sk.public_key();
+3 -2
View File
@@ -141,8 +141,8 @@ impl<T> From<InternalError> for ProtocolError<T> {
// See https://github.com/rust-lang/rust/issues/64715 and remove this when merged,
// and https://github.com/dtolnay/thiserror/issues/62 for why this comes up in our
// doc tests.
impl<T> From<::core::convert::Infallible> for ProtocolError<T> {
fn from(_: ::core::convert::Infallible) -> Self {
impl<T> From<Infallible> for ProtocolError<T> {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
@@ -164,6 +164,7 @@ impl ProtocolError {
actual_len,
},
Self::ReflectedValueError => ProtocolError::ReflectedValueError,
Self::Custom(infallible) => match infallible {},
}
}
}
+27 -15
View File
@@ -8,36 +8,45 @@
//! A convenience trait for digest bounds used throughout the library
use digest::block_api::{
BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, SmallBlockSizeUser,
};
use digest::block_buffer::Eager;
use digest::core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore};
use digest::{FixedOutputReset, HashMarker, OutputSizeUser};
use digest::{Digest, FixedOutputReset, HashMarker, OutputSizeUser};
use generic_array::typenum::{IsLess, Le, NonZero, U256};
pub(crate) type OutputSize<H> = <<H as CoreProxy>::Core as OutputSizeUser>::OutputSize;
/// Trait to simplify requirements for [`Hash`].
pub trait ProxyHash:
HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone
HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + OutputSizeUser + Default + Clone
where
<Self as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero,
<Self as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<Self as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
{
}
impl<T: HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone>
ProxyHash for T
impl<
T: HashMarker
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ OutputSizeUser
+ Default
+ Clone,
> ProxyHash for T
where
<Self as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero,
<T as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<T as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
{
}
/// Trait inheriting the requirements from [`digest::Digest`] for compatibility
/// Trait inheriting the requirements from [`Digest`] for compatibility
/// with HKDF and HMAC Associated types could be simplified when they are made
/// as defaults: <https://github.com/rust-lang/rust/issues/29661>
pub trait Hash:
Default
+ HashMarker
+ Digest
+ OutputSizeUser<OutputSize = OutputSize<Self>>
+ BlockSizeUser
+ FixedOutputReset
@@ -45,14 +54,16 @@ pub trait Hash:
+ Clone
where
<Self as CoreProxy>::Core: ProxyHash,
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<Self>: generic_array::ArrayLength,
{
}
impl<
T: Default
+ HashMarker
+ Digest
+ OutputSizeUser<OutputSize = OutputSize<Self>>
+ BlockSizeUser
+ FixedOutputReset
@@ -60,8 +71,9 @@ impl<
+ Clone,
> Hash for T
where
<Self as CoreProxy>::Core: ProxyHash,
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<T as CoreProxy>::Core: ProxyHash,
<<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<T>: generic_array::ArrayLength,
{
}
+2 -2
View File
@@ -14,7 +14,7 @@ use curve25519_dalek::scalar;
use curve25519_dalek::traits::IsIdentity;
use generic_array::GenericArray;
use generic_array::typenum::U32;
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use subtle::ConstantTimeEq;
use zeroize::ZeroizeOnDrop;
@@ -43,7 +43,7 @@ impl Group for Curve25519 {
.and_then(|bytes| NonIdentity::from_bytes(bytes.into()))
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
// Sample 32 random bytes and then clamp, as described in https://cr.yp.to/ecdh.html
let mut scalar_bytes = [0u8; 32];
rng.fill_bytes(&mut scalar_bytes);
+16 -15
View File
@@ -18,9 +18,8 @@ pub use ed25519_dalek;
use ed25519_dalek::hazmat::ExpandedSecretKey;
use ed25519_dalek::{SecretKey, Sha512};
use generic_array::GenericArray;
use generic_array::sequence::Concat;
use generic_array::typenum::{U32, U64};
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use zeroize::{Zeroize, ZeroizeOnDrop};
use super::Group;
@@ -30,7 +29,7 @@ use crate::key_exchange::sigma_i::hash_eddsa::implementation::HashEddsaImpl;
use crate::key_exchange::sigma_i::pure_eddsa::implementation::PureEddsaImpl;
pub use crate::key_exchange::sigma_i::shared::PreHash;
use crate::key_exchange::sigma_i::{CachedMessage, Message, MessageBuilder};
use crate::serialization::{SliceExt, UpdateExt};
use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// Implementation for Ed25519.
pub struct Ed25519;
@@ -46,12 +45,12 @@ impl Group for Ed25519 {
}
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
let bytes = bytes.take_array("public key")?;
let bytes = bytes.take_array::<U32>("public key")?;
VerifyingKey::from_bytes(bytes.into())
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
let mut sk = <[u8; 32]>::default();
rng.fill_bytes(&mut sk);
@@ -72,7 +71,7 @@ impl Group for Ed25519 {
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
Ok(SigningKey::from_bytes(
bytes.take_array("secret key")?.into(),
bytes.take_array::<U32>("secret key")?.into(),
))
}
}
@@ -399,7 +398,7 @@ pub struct Signature {
}
impl Signature {
/// Expects the `R` and `s` components of a Ed25519 signature with no added
/// Expects the `R` and `s` components of an Ed25519 signature with no added
/// framing.
pub fn from_slice(mut bytes: &[u8]) -> Result<Self, ProtocolError> {
Self::deserialize_take(&mut bytes)
@@ -407,9 +406,9 @@ impl Signature {
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
#[allow(non_snake_case)]
let R = CompressedEdwardsY(bytes.take_array("signature R")?.into());
let R = CompressedEdwardsY(bytes.take_array::<U32>("signature R")?.into());
let s = Scalar::from_canonical_bytes(bytes.take_array("signature s")?.into())
let s = Scalar::from_canonical_bytes(bytes.take_array::<U32>("signature s")?.into())
.into_option()
.ok_or(ProtocolError::SerializationError)?;
@@ -417,7 +416,8 @@ impl Signature {
}
fn serialize(&self) -> GenericArray<u8, U64> {
GenericArray::from(self.R.0).concat(GenericArray::from(self.s.to_bytes()))
GenericArray::<u8, U32>::from(self.R.0)
.cat(GenericArray::<u8, U32>::from(self.s.to_bytes()))
}
}
@@ -433,17 +433,18 @@ mod test {
use std::iter;
use ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey};
use rand::rngs::OsRng;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use super::*;
#[test]
fn pure_eddsa() {
let mut message = [0; 1024];
OsRng.fill_bytes(&mut message);
UnwrapErr(SysRng).fill_bytes(&mut message);
let mut sk = SecretKey::default();
OsRng.fill_bytes(&mut sk);
UnwrapErr(SysRng).fill_bytes(&mut sk);
let signing_key = SigningKey::from_bytes(&sk);
let signature = signing_key.sign(&message);
@@ -472,12 +473,12 @@ mod test {
#[test]
fn hash_eddsa() {
let mut message = [0; 1024];
OsRng.fill_bytes(&mut message);
UnwrapErr(SysRng).fill_bytes(&mut message);
let message = Sha512::new_with_prefix(message);
let pre_hash = message.clone().finalize();
let mut sk = SecretKey::default();
OsRng.fill_bytes(&mut sk);
UnwrapErr(SysRng).fill_bytes(&mut sk);
let signing_key = SigningKey::from_bytes(&sk);
let signature = signing_key.sign_prehashed(message.clone(), None).unwrap();
+50 -67
View File
@@ -8,17 +8,18 @@
//! Implementation for EC curves via [`elliptic_curve`] traits.
use core::fmt::{self, Debug, Formatter};
use derive_where::derive_where;
use core::ops::Mul;
use digest::OutputSizeUser;
use digest::block_api::BlockSizeUser;
use elliptic_curve::group::GroupEncoding;
use elliptic_curve::ops::MulByGenerator;
use elliptic_curve::sec1::{ModulusSize, ToEncodedPoint};
use elliptic_curve::point::NonIdentity;
use elliptic_curve::sec1::{ModulusSize, ToSec1Point};
use elliptic_curve::{
CurveArithmetic, FieldBytesSize, NonZeroScalar, ProjectivePoint, Scalar, SecretKey, point,
CurveArithmetic, FieldBytesSize, Generate, NonZeroScalar, ProjectivePoint, Scalar, SecretKey,
};
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, Rng};
use voprf::Mode;
use super::{Group, STR_OPAQUE_DERIVE_AUTH_KEY_PAIR};
@@ -29,15 +30,27 @@ use crate::serialization::SliceExt;
impl<G> Group for G
where
Self: CurveArithmetic + voprf::CipherSuite<Group = Self> + voprf::Group<Scalar = Scalar<Self>>,
FieldBytesSize<Self>: ModulusSize,
FieldBytesSize<Self>: ModulusSize + ArrayLength,
<FieldBytesSize<Self> as ModulusSize>::CompressedPointSize: ArrayLength,
ProjectivePoint<Self>: GroupEncoding<
Repr = GenericArray<u8, <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize>,
> + ToEncodedPoint<Self>,
Repr = hybrid_array::Array<
u8,
<FieldBytesSize<Self> as ModulusSize>::CompressedPointSize,
>,
> + ToSec1Point<Self>,
// Bounds required by voprf::CipherSuite
<Self as voprf::Group>::SecurityLevel: Mul<U2>,
<<Self as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize: ArrayLength
+ IsLess<U256>
+ IsLessOrEqual<
<<Self as voprf::CipherSuite>::Hash as BlockSizeUser>::BlockSize,
Output = True,
> + IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{
// We don't use `elliptic_curve::PublicKey` because it stores its internals in a
// format ideal for serialization and not computation. This is inconsistent with
// our other implementations.
type Pk = NonIdentity<Self>;
type Pk = NonIdentity<ProjectivePoint<Self>>;
type PkLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
@@ -46,18 +59,19 @@ where
type SkLen = FieldBytesSize<Self>;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(pk.0.to_encoded_point(true).as_bytes())
GenericArray::from_slice(pk.to_sec1_point(true).as_bytes()).clone()
}
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
point::NonIdentity::<ProjectivePoint<Self>>::from_bytes(&bytes.take_array("public key")?)
.into_option()
.map(NonIdentity)
.ok_or(ProtocolError::SerializationError)
NonIdentity::<ProjectivePoint<Self>>::from_bytes(
&bytes.take_array("public key")?.into_ha0_4(),
)
.into_option()
.ok_or(ProtocolError::SerializationError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
SecretKey::<Self>::random(rng)
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
SecretKey::<Self>::generate_from_rng(rng)
}
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> {
@@ -70,21 +84,15 @@ where
}
fn public_key(sk: &Self::Sk) -> Self::Pk {
// Non-panicking version in https://github.com/RustCrypto/traits/pull/1833.
NonIdentity(
point::NonIdentity::new(ProjectivePoint::<Self>::mul_by_generator(
&sk.to_nonzero_scalar(),
))
.expect("multiplying with a non-zero scalar can never yield the identity element"),
)
NonIdentity::<ProjectivePoint<Self>>::mul_by_generator(&sk.to_nonzero_scalar())
}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes()
GenericArray::from(sk.to_bytes())
}
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
SecretKey::<Self>::from_bytes(&bytes.take_array("secret key")?)
SecretKey::<Self>::from_bytes(&bytes.take_array("secret key")?.into_ha0_4())
.map_err(|_| ProtocolError::SerializationError)
}
}
@@ -92,51 +100,26 @@ where
impl<G> DiffieHellman<G> for SecretKey<G>
where
G: CurveArithmetic + voprf::CipherSuite<Group = G> + voprf::Group<Scalar = Scalar<G>>,
FieldBytesSize<G>: ModulusSize,
FieldBytesSize<G>: ModulusSize + ArrayLength,
<FieldBytesSize<G> as ModulusSize>::CompressedPointSize: ArrayLength,
ProjectivePoint<G>: GroupEncoding<
Repr = GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>,
> + ToEncodedPoint<G>,
Repr = hybrid_array::Array<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>,
> + ToSec1Point<G>,
<G as voprf::Group>::SecurityLevel: Mul<U2>,
<<G as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize: ArrayLength
+ IsLess<U256>
+ IsLessOrEqual<<<G as voprf::CipherSuite>::Hash as BlockSizeUser>::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<G as voprf::Group>::SecurityLevel, U2>, Output = True>,
{
fn diffie_hellman(
&self,
pk: &NonIdentity<G>,
pk: &NonIdentity<ProjectivePoint<G>>,
) -> GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize> {
GenericArray::clone_from_slice(
(pk.0 * self.to_nonzero_scalar())
.to_encoded_point(true)
GenericArray::from_slice(
(pk * self.to_nonzero_scalar())
.to_sec1_point(true)
.as_bytes(),
)
.clone()
}
}
/// Wrapper around [`NonIdentity`](point::NonIdentity) to [`Eq`].
// TODO: remove after https://github.com/RustCrypto/traits/pull/1834.
#[derive_where(Clone, Copy)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "point::NonIdentity<ProjectivePoint<G>>: serde::Deserialize<'de>",
serialize = "point::NonIdentity<ProjectivePoint<G>>: serde::Serialize"
),
transparent
)
)]
pub struct NonIdentity<G: CurveArithmetic>(pub point::NonIdentity<ProjectivePoint<G>>);
impl<G: CurveArithmetic> Debug for NonIdentity<G> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("NonIdentity")
.field(&self.0.to_point())
.finish()
}
}
impl<G: CurveArithmetic> PartialEq for NonIdentity<G> {
fn eq(&self, other: &Self) -> bool {
self.0.to_point().eq(&other.0.to_point())
}
}
impl<G: CurveArithmetic> Eq for NonIdentity<G> {}
+5 -4
View File
@@ -17,7 +17,8 @@ pub mod elliptic_curve;
pub mod ristretto255;
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use hybrid_array::ArraySize;
use rand::{CryptoRng, Rng};
use zeroize::ZeroizeOnDrop;
use crate::errors::{InternalError, ProtocolError};
@@ -29,11 +30,11 @@ pub trait Group {
/// Public key
type Pk: Clone;
/// Length of the public key
type PkLen: ArrayLength<u8>;
type PkLen: ArrayLength + ArraySize;
/// Secret key
type Sk: Clone + ZeroizeOnDrop;
/// Length of the secret key
type SkLen: ArrayLength<u8>;
type SkLen: ArrayLength + ArraySize;
/// Serializes `self`
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen>;
@@ -44,7 +45,7 @@ pub trait Group {
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError>;
/// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk;
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk;
/// Deterministically derive a [`Self::Sk`] from `seed`.
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>;
+24 -13
View File
@@ -13,11 +13,12 @@ use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::IsIdentity;
use digest::core_api::BlockSizeUser;
use digest::block_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker};
use generic_array::GenericArray;
use generic_array::typenum::{IsLess, IsLessOrEqual, U32, U256};
use rand::{CryptoRng, RngCore};
use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U32, U256};
use hybrid_array::Array;
use rand::{CryptoRng, Rng, TryCryptoRng, TryRng};
use voprf::Mode;
use zeroize::ZeroizeOnDrop;
@@ -42,15 +43,19 @@ impl Group for Ristretto255 {
}
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
CompressedRistretto(bytes.take_array("public key")?.into())
CompressedRistretto(bytes.take_array::<U32>("public key")?.into())
.decompress()
.ok_or(ProtocolError::SerializationError)
.and_then(NonIdentity::from_point)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
loop {
let scalar = Scalar::random(rng);
let mut bytes = [0u8; 64];
rng.fill_bytes(&mut bytes);
let scalar = Scalar::from_bytes_mod_order_wide(&bytes);
if scalar != Scalar::ZERO {
break NonZeroScalar(scalar);
@@ -73,7 +78,7 @@ impl Group for Ristretto255 {
}
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
Scalar::from_canonical_bytes(bytes.take_array("secret key")?.into())
Scalar::from_canonical_bytes(bytes.take_array::<U32>("secret key")?.into())
.into_option()
.ok_or(ProtocolError::SerializationError)
.and_then(NonZeroScalar::from_scalar)
@@ -149,7 +154,7 @@ where
}
impl voprf::CipherSuite for Ristretto255 {
const ID: &'static str = voprf::Ristretto255::ID;
const ID: &'static [u8] = voprf::Ristretto255::ID;
type Group = <voprf::Ristretto255 as voprf::CipherSuite>::Group;
@@ -165,13 +170,17 @@ impl voprf::Group for Ristretto255 {
type ScalarLen = <voprf::Ristretto255 as voprf::Group>::ScalarLen;
type SecurityLevel = <voprf::Ristretto255 as voprf::Group>::SecurityLevel;
fn hash_to_curve<H>(
input: &[&[u8]],
dst: &[&[u8]],
) -> voprf::Result<Self::Elem, voprf::InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
H::OutputSize: IsLess<U256>
+ IsLessOrEqual<H::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{
<voprf::Ristretto255 as voprf::Group>::hash_to_curve::<H>(input, dst)
}
@@ -182,7 +191,9 @@ impl voprf::Group for Ristretto255 {
) -> voprf::Result<Self::Scalar, voprf::InternalError>
where
H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
H::OutputSize: IsLess<U256>
+ IsLessOrEqual<H::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{
<voprf::Ristretto255 as voprf::Group>::hash_to_scalar::<H>(input, dst)
}
@@ -195,7 +206,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::identity_elem()
}
fn serialize_elem(elem: Self::Elem) -> GenericArray<u8, Self::ElemLen> {
fn serialize_elem(elem: Self::Elem) -> Array<u8, Self::ElemLen> {
<voprf::Ristretto255 as voprf::Group>::serialize_elem(elem)
}
@@ -203,7 +214,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::deserialize_elem(element_bits)
}
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
fn random_scalar<R: TryRng + TryCryptoRng>(rng: &mut R) -> voprf::Result<Self::Scalar> {
<voprf::Ristretto255 as voprf::Group>::random_scalar(rng)
}
@@ -215,7 +226,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::is_zero_scalar(scalar)
}
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> {
fn serialize_scalar(scalar: Self::Scalar) -> Array<u8, Self::ScalarLen> {
<voprf::Ristretto255 as voprf::Group>::serialize_scalar(scalar)
}
+32 -22
View File
@@ -21,11 +21,12 @@ use core::ops::Add;
use derive_where::derive_where;
use digest::Output;
use digest::core_api::{BlockSizeUser, CoreProxy};
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U2, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use hybrid_array::Array;
use rand::{CryptoRng, Rng};
use voprf::{BlindedElement, EvaluationElement};
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -33,7 +34,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::ciphersuite::KeHash;
use crate::ciphersuite::{CipherSuite, OprfGroup};
use crate::errors::ProtocolError;
use crate::hash::{Hash, ProxyHash};
use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::Group;
use crate::key_exchange::shared::{NonceLen, STR_CONTEXT};
use crate::keypair::{PrivateKey, PublicKey};
@@ -44,8 +45,9 @@ use crate::serialization::{SliceExt, i2osp};
pub trait KeyExchange
where
<Self::Hash as CoreProxy>::Core: ProxyHash,
<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<Self::Hash>: ArrayLength,
{
/// The group used for the key exchange.
type Group: Group;
@@ -71,12 +73,12 @@ where
/// Client generates [`KE1Message`](Self::KE1Message) and
/// [`KE1State`](Self::KE1State).
fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError>;
/// Server generates [`KE2Builder`](Self::KE2Builder).
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>(
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -92,7 +94,7 @@ where
) -> Self::KE2BuilderData<'a, CS>;
/// Server generates the input without a remote key.
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>,
rng: &mut R,
server_s_sk: &PrivateKey<Self::Group>,
@@ -107,7 +109,7 @@ where
/// Client generates [`KE3Message`](Self::KE3Message) and the session key.
#[allow(clippy::too_many_arguments)]
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -137,7 +139,7 @@ where
)]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
pub struct SerializedCredentialRequest<CS: CipherSuite>(
GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
);
impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
@@ -154,17 +156,20 @@ impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
/// Returns a [`SerializedCredentialRequest`] deserialized from the given
/// `bytes`.
pub fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self(bytes.take_array("blinded element")?))
Ok(Self(bytes.take_array("blinded element")?.into_ha0_4()))
}
}
type SerializedCredentialRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Group>::ElemLen;
impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS> {
impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS>
where
<OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
{
type Len = SerializedCredentialRequestLen<CS>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone()
GenericArray::from_slice(self.0.as_slice()).clone()
}
}
@@ -176,7 +181,7 @@ impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS> {
)]
#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
pub struct SerializedCredentialResponse<CS: CipherSuite> {
evaluation_element: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
evaluation_element: Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
masking_nonce: GenericArray<u8, NonceLen>,
masked_response: MaskedResponse<CS>,
}
@@ -207,7 +212,7 @@ impl<CS: CipherSuite> SerializedCredentialResponse<CS> {
/// `bytes`.
pub fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
evaluation_element: input.take_array("evaluation element")?,
evaluation_element: input.take_array("evaluation element")?.into_ha0_4(),
masking_nonce: input.take_array("masking nonce")?,
masked_response: MaskedResponse::deserialize_take(input)?,
})
@@ -221,16 +226,21 @@ impl<CS: CipherSuite> Serialize for SerializedCredentialResponse<CS>
where
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength,
{
type Len = SerializedCredentialResponseLen<CS>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.evaluation_element
.clone()
.concat(self.masking_nonce)
.concat(self.masked_response.serialize())
let elem = GenericArray::<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>::from_slice(
self.evaluation_element.as_slice(),
)
.clone();
Concat::concat(
Concat::concat(elem, self.masking_nonce),
self.masked_response.serialize(),
)
}
}
@@ -359,7 +369,7 @@ pub trait Deserialize: Sized {
/// Serialization trait for key exchange types.
pub trait Serialize {
/// The length of the serialized types.
type Len: ArrayLength<u8>;
type Len: ArrayLength;
/// Serialize [`Self`] to a fixed-length byte array.
fn serialize(&self) -> GenericArray<u8, Self::Len>;
+45 -34
View File
@@ -9,14 +9,15 @@
use core::ops::Add;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use digest::{Digest, Mac, Output, OutputSizeUser, Update};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U1, U2, U32, U256, Unsigned};
use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract};
use hmac::Hmac;
use rand::{CryptoRng, RngCore};
use hkdf::SimpleHkdf as Hkdf;
use hkdf::SimpleHkdfExtract as HkdfExtract;
use hmac::{KeyInit, SimpleHmac};
use rand::{CryptoRng, Rng};
use super::{
Deserialize, GenerateKe1Result, KeyExchange, Serialize, SerializedContext,
@@ -106,8 +107,9 @@ pub(super) struct DerivedKeys<H: OutputSizeUser> {
pub(super) struct Ke2BuilderCommon<G: Group, H: Hash>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
G::Sk: DiffieHellman<G>,
{
pub(super) server_nonce: GenericArray<u8, NonceLen>,
@@ -126,7 +128,7 @@ where
// Helper functions
pub(super) fn generate_ke1<
R: RngCore + CryptoRng,
R: Rng + CryptoRng,
KE: KeyExchange<KE1State = Ke1State<G>, KE1Message = Ke1Message<G>>,
G: Group,
>(
@@ -150,7 +152,7 @@ pub(super) fn generate_ke1<
}
// Generate a random nonce up to NonceLen::USIZE bytes.
pub(super) fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, NonceLen> {
pub(super) fn generate_nonce<R: Rng + CryptoRng>(rng: &mut R) -> GenericArray<u8, NonceLen> {
let mut nonce_bytes = GenericArray::default();
rng.fill_bytes(&mut nonce_bytes);
nonce_bytes
@@ -190,11 +192,12 @@ pub(super) fn ke2_builder_common<'a, G, H, CS, R>(
where
G: Group,
H: Hash,
R: RngCore + CryptoRng,
R: Rng + CryptoRng,
CS: CipherSuite,
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
G::Sk: DiffieHellman<G>,
CS::KeyExchange: KeyExchange<Group = G, Hash = H>,
{
@@ -238,8 +241,9 @@ pub(super) fn derive_keys<'a, H: Hash>(
) -> Result<DerivedKeys<H>, ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
let mut hkdf = HkdfExtract::<H>::new(None);
@@ -280,19 +284,20 @@ pub(super) fn compute_ke2_macs<H: Hash>(
) -> Result<(Output<H>, Output<H>), ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
let mut mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
SimpleHmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut mac_hasher, transcript_digest);
let mac = mac_hasher.finalize().into_bytes();
transcript_hasher.update(&mac);
Update::update(transcript_hasher, &mac);
let finalized_transcript = transcript_hasher.clone().finalize();
let mut expected_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
SimpleHmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut expected_mac_hasher, &finalized_transcript);
let expected_mac = expected_mac_hasher.finalize().into_bytes();
@@ -311,23 +316,24 @@ pub(super) fn finalize_ke3_transcript<'a, H: Hash>(
) -> Result<(DerivedKeys<H>, Output<H>), ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
let transcript_digest = transcript_hasher.clone().finalize();
let derived_keys = derive_keys::<H>(shared_secrets, &transcript_digest)?;
let mut server_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
SimpleHmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut server_mac_hasher, &transcript_digest);
server_mac_hasher
.verify(server_mac)
.map_err(|_| ProtocolError::InvalidLoginError)?;
transcript_hasher.update(server_mac.as_slice());
Update::update(transcript_hasher, server_mac);
let finalized_transcript = transcript_hasher.clone().finalize();
let mut client_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
SimpleHmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut client_mac_hasher, &finalized_transcript);
let client_mac = client_mac_hasher.finalize().into_bytes();
@@ -342,8 +348,9 @@ fn hkdf_expand_label<H: Hash>(
) -> Result<Output<H>, ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
let h = Hkdf::<H>::from_prk(secret).map_err(|_| InternalError::HkdfError)?;
hkdf_expand_label_extracted(&h, label, context)
@@ -356,10 +363,11 @@ fn hkdf_expand_label_extracted<H: Hash>(
) -> Result<Output<H>, ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
let mut okm = GenericArray::default();
let mut okm = GenericArray::default().into_ha0_4();
let length = i2osp::<U2>(OutputSize::<H>::USIZE)?;
let label_length = i2osp::<U1>(STR_OPAQUE.len() + label.len())?;
@@ -386,8 +394,9 @@ fn derive_secrets<H: Hash>(
) -> Result<Output<H>, ProtocolError>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
hkdf_expand_label_extracted::<H>(hkdf, label, hashed_derivation_transcript)
}
@@ -407,12 +416,14 @@ impl<G: Group> Serialize for Ke1State<G>
where
// Ke1State: KeSk + Nonce
G::SkLen: Add<NonceLen>,
Sum<G::SkLen, NonceLen>: ArrayLength<u8>,
Sum<G::SkLen, NonceLen>: ArrayLength,
{
type Len = Sum<G::SkLen, NonceLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_e_sk.serialize().concat(self.client_nonce)
let a = self.client_e_sk.serialize();
GenericArray::concat(a, self.client_nonce)
}
}
@@ -429,7 +440,7 @@ impl<G: Group> Serialize for Ke1Message<G>
where
// Ke1Message: Nonce + KePk
NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8>,
Sum<NonceLen, G::PkLen>: ArrayLength,
{
type Len = Sum<NonceLen, G::PkLen>;
@@ -476,7 +487,7 @@ impl<G: Group> Ke1MessageIter<G> {
impl<G: Group> Ke1MessageIter<G>
where
NonceLen: Add<G::PkLen>,
Ke1MessageIterLen<G>: ArrayLength<u8>,
Ke1MessageIterLen<G>: ArrayLength,
{
pub(crate) fn serialize(&self) -> GenericArray<u8, Ke1MessageIterLen<G>> {
self.client_nonce.concat(self.client_e_pk.clone())
+40 -85
View File
@@ -11,23 +11,19 @@
use core::marker::PhantomData;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{FixedOutputReset, HashMarker};
use ecdsa::{PrimeCurve, SignatureSize, hazmat};
use elliptic_curve::{
CurveArithmetic, Field, FieldBytes, FieldBytesEncoding, FieldBytesSize, PrimeField, Scalar,
SecretKey,
};
use digest::block_api::{BlockSizeUser, EagerHash};
use digest::{Digest, FixedOutputReset, HashMarker};
use ecdsa::{EcdsaCurve, SignatureSize};
use elliptic_curve::point::NonIdentity;
use elliptic_curve::{CurveArithmetic, FieldBytes, ProjectivePoint, SecretKey};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
use hybrid_array::ArraySize;
use rand::{CryptoRng, Rng};
use super::{Message, MessageBuilder, SignatureProtocol};
use crate::ciphersuite::CipherSuite;
use crate::errors::ProtocolError;
use crate::key_exchange::group::Group;
use crate::key_exchange::group::elliptic_curve::NonIdentity;
pub use crate::key_exchange::sigma_i::shared::PreHash;
use crate::serialization::SliceExt;
@@ -39,23 +35,21 @@ pub struct Ecdsa<G, H>(PhantomData<(G, H)>);
impl<G, H> SignatureProtocol for Ecdsa<G, H>
where
G: CurveArithmetic + Group<Sk = SecretKey<G>, Pk = NonIdentity<G>> + PrimeCurve,
SignatureSize<G>: ArrayLength<u8>,
H: Clone
+ Default
+ BlockSizeUser
+ FixedOutputReset<OutputSize = FieldBytesSize<G>>
+ HashMarker,
G: CurveArithmetic
+ Group<Sk = SecretKey<G>, Pk = NonIdentity<ProjectivePoint<G>>>
+ EcdsaCurve,
SignatureSize<G>: ArrayLength + ArraySize,
H: EagerHash + FixedOutputReset + BlockSizeUser + HashMarker + Digest + Clone + Default,
{
type Group = G;
type Signature = Signature<G>;
type Signature = ecdsa::Signature<G>;
type SignatureLen = SignatureSize<G>;
type VerifyState<CS: CipherSuite, KE: Group> = PreHash<H>;
// We use a manual implementation of `RandomizedPrehashSigner` to use the same
// hash for the message as for generating `k`. See
// https://github.com/RustCrypto/signatures/issues/949.
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>(
fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk,
rng: &mut R,
message: &Message<CS, KE>,
@@ -63,7 +57,7 @@ where
let hash = message.hash::<H>();
(
Signature(sign::<_, G, H>(sk, rng, &hash.sign.finalize_fixed())),
sign::<_, G, H>(sk, rng, &hash.sign.finalize_fixed()),
PreHash(hash.verify.finalize_fixed()),
)
}
@@ -74,96 +68,55 @@ where
state: Self::VerifyState<CS, KE>,
signature: &Self::Signature,
) -> Result<(), ProtocolError> {
verify(pk, &state.0, &signature.0)
verify(pk, &state.0, signature)
}
fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> {
signature.0.to_bytes()
GenericArray::from_slice(signature.to_bytes().as_slice()).clone()
}
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
ecdsa::Signature::from_bytes(&bytes.take_array("signature")?)
.map(Signature)
ecdsa::Signature::from_bytes(&bytes.take_array("signature")?.into_ha0_4())
.map_err(|_| ProtocolError::SerializationError)
}
}
fn sign<R, C, H>(sk: &SecretKey<C>, rng: &mut R, pre_hash: &[u8]) -> ecdsa::Signature<C>
where
R: CryptoRng + RngCore,
C: CurveArithmetic + PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
H: Default + BlockSizeUser + FixedOutputReset<OutputSize = FieldBytesSize<C>> + HashMarker,
R: CryptoRng + Rng,
C: CurveArithmetic + EcdsaCurve,
SignatureSize<C>: ArraySize,
H: Digest + BlockSizeUser + FixedOutputReset,
{
let repr = sk.to_bytes();
let order = C::ORDER.encode_field_bytes();
let z =
hazmat::bits2field::<C>(pre_hash).expect("hash output can not be shorter than a scalar");
// This can only fail if the computed `r` or `s` are zero, in which case we just
// retry with a new `k`. See https://github.com/RustCrypto/signatures/pull/951.
loop {
let mut ad = FieldBytes::<C>::default();
rng.fill_bytes(&mut ad);
let k =
Scalar::<C>::from_repr(rfc6979::generate_k::<H, _>(&repr, &order, &z, &ad)).unwrap();
if let Ok((signature, _)) = hazmat::sign_prehashed::<C, _>(&sk.to_nonzero_scalar(), k, &z) {
break signature;
}
}
let mut ad = FieldBytes::<C>::default();
rng.fill_bytes(&mut ad);
ecdsa::hazmat::sign_prehashed_rfc6979::<C, H>(&sk.to_nonzero_scalar(), pre_hash, &ad).0
}
fn verify<C>(
pk: &NonIdentity<C>,
pk: &NonIdentity<ProjectivePoint<C>>,
pre_hash: &[u8],
signature: &ecdsa::Signature<C>,
) -> Result<(), ProtocolError>
where
C: CurveArithmetic + PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
C: CurveArithmetic + EcdsaCurve,
SignatureSize<C>: ArraySize,
{
let z =
hazmat::bits2field::<C>(pre_hash).expect("hash output can not be shorter than a scalar");
hazmat::verify_prehashed(&pk.0.to_point(), &z, signature)
ecdsa::hazmat::verify_prehashed(&pk.to_point(), pre_hash, signature)
.map_err(|_| ProtocolError::InvalidLoginError)
}
/// Wrapper around [`ecdsa::Signature`] to implement [`Zeroize`].
// TODO: remove after https://github.com/RustCrypto/signatures/pull/948.
#[derive_where(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", transparent)
)]
pub struct Signature<G: CurveArithmetic + PrimeCurve>(pub ecdsa::Signature<G>)
where
SignatureSize<G>: ArrayLength<u8>;
impl<G: CurveArithmetic + PrimeCurve> Zeroize for Signature<G>
where
SignatureSize<G>: ArrayLength<u8>,
{
fn zeroize(&mut self) {
self.0 = ecdsa::Signature::from_scalars(
Into::<FieldBytes<G>>::into(Scalar::<G>::ONE),
Into::<FieldBytes<G>>::into(Scalar::<G>::ONE),
)
.expect("failed to create `Signature` with non-zero `Scalar`s");
}
}
#[test]
fn ecdsa() {
use std::vec;
use digest::Digest;
use p256::ecdsa::signature::{DigestVerifier, RandomizedDigestSigner};
use ecdsa::signature::hazmat::PrehashVerifier;
use p256::ecdsa::signature::RandomizedDigestSigner;
use p256::ecdsa::{Signature, SigningKey, VerifyingKey};
use p256::{NistP256, PublicKey};
use rand::rngs::OsRng;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use sha2::Sha256;
use crate::tests::mock_rng::CycleRng;
@@ -171,22 +124,24 @@ fn ecdsa() {
let mut rng = CycleRng::new(vec![1; 32]);
let mut message = [0; 1024];
OsRng.fill_bytes(&mut message);
UnwrapErr(SysRng).fill_bytes(&mut message);
let hash = Sha256::new_with_prefix(message);
let sk = NistP256::random_sk(&mut OsRng);
let sk = NistP256::random_sk(&mut UnwrapErr(SysRng));
let signing_key = SigningKey::from(sk.clone());
let signature: Signature = signing_key.sign_digest_with_rng(&mut rng, hash.clone());
let signature: Signature = signing_key.sign_digest_with_rng(&mut rng, |d: &mut Sha256| {
d.update(message);
});
let custom_signature = sign::<_, _, Sha256>(&sk, &mut rng, &hash.clone().finalize());
assert_eq!(signature, custom_signature);
let pk = NistP256::public_key(&sk);
let verifying_key = VerifyingKey::from(PublicKey::from(pk.0));
let verifying_key = VerifyingKey::from(PublicKey::from(&pk));
verifying_key
.verify_digest(hash.clone(), &signature)
.verify_prehash(&hash.clone().finalize(), &signature)
.unwrap();
verify(&pk, &hash.finalize(), &custom_signature).unwrap();
}
+3 -3
View File
@@ -12,7 +12,7 @@
use core::marker::PhantomData;
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use zeroize::Zeroize;
use self::implementation::HashEddsaImpl;
@@ -33,7 +33,7 @@ impl<G: HashEddsaImpl> SignatureProtocol for HashEddsa<G> {
type SignatureLen = G::SignatureLen;
type VerifyState<CS: CipherSuite, KE: Group> = G::VerifyState<CS, KE>;
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>(
fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk,
_: &mut R,
message: &Message<CS, KE>,
@@ -66,7 +66,7 @@ pub(in super::super) mod implementation {
pub trait HashEddsaImpl: Group {
type Signature: Clone + Zeroize;
type SignatureLen: ArrayLength<u8>;
type SignatureLen: ArrayLength;
type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize;
fn sign<CS: CipherSuite, KE: Group>(
+16 -17
View File
@@ -10,7 +10,6 @@ use core::ops::Add;
use derive_where::derive_where;
use digest::{FixedOutput, Output, Update};
use generic_array::sequence::Concat;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use zeroize::Zeroize;
@@ -26,7 +25,7 @@ use crate::key_exchange::{
SerializedIdentifier, SerializedIdentifiers,
};
use crate::opaque::MaskedResponseLen;
use crate::serialization::{SliceExt, UpdateExt};
use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// This holds the message to be signed and the message to be verified.
///
@@ -242,7 +241,7 @@ impl<CS: CipherSuite, KE: Group> Deserialize for CachedMessage<CS, KE> {
credential_response: SerializedCredentialResponse::deserialize_take(input)?,
server_nonce: input.take_array("server nonce")?,
server_e_pk: input.take_array("serialized server ephemeral key")?,
server_mac: input.take_array("server mac")?,
server_mac: input.take_array("server mac")?.into_ha0_4(),
})
}
}
@@ -264,20 +263,20 @@ type CachedMessageLen<CS: CipherSuite, KE: Group> = Sum<
impl<CS: CipherSuite, KE: Group> Serialize for CachedMessage<CS, KE>
where
SerializedCredentialRequestLen<CS>: ArrayLength<u8> + Add<Ke1MessageIterLen<KE>>,
SerializedCredentialRequestLen<CS>: ArrayLength + Add<Ke1MessageIterLen<KE>>,
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>:
ArrayLength<u8> + Add<SerializedCredentialResponseLen<CS>>,
ArrayLength + Add<SerializedCredentialResponseLen<CS>>,
Sum<
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
SerializedCredentialResponseLen<CS>,
>: ArrayLength<u8> + Add<NonceLen>,
>: ArrayLength + Add<NonceLen>,
Sum<
Sum<
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
SerializedCredentialResponseLen<CS>,
>,
NonceLen,
>: ArrayLength<u8> + Add<KE::PkLen>,
>: ArrayLength + Add<KE::PkLen>,
Sum<
Sum<
Sum<
@@ -287,26 +286,26 @@ where
NonceLen,
>,
KE::PkLen,
>: ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>,
CachedMessageLen<CS, KE>: ArrayLength<u8>,
>: ArrayLength + Add<OutputSize<KeHash<CS>>>,
CachedMessageLen<CS, KE>: ArrayLength,
// Ke1MessageIter
NonceLen: Add<KE::PkLen>,
Ke1MessageIterLen<KE>: ArrayLength<u8>,
Ke1MessageIterLen<KE>: ArrayLength,
// CredentialResponseParts
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength,
{
type Len = CachedMessageLen<CS, KE>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.credential_request
.serialize()
.concat(self.ke1_message.serialize())
.concat(self.credential_response.serialize())
.concat(self.server_nonce)
.concat(self.server_e_pk.clone())
.concat(self.server_mac.clone())
.cat(self.ke1_message.serialize())
.cat(self.credential_response.serialize())
.cat(self.server_nonce)
.cat(self.server_e_pk.clone())
.cat(GenericArray::from_slice(self.server_mac.as_slice()).clone())
}
}
+75 -55
View File
@@ -23,13 +23,13 @@ use core::marker::PhantomData;
use core::ops::Add;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Mac, Output, OutputSizeUser};
use digest::block_api::{BlockSizeUser, CoreProxy, SmallBlockSizeUser};
use digest::{Mac, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray};
use hmac::Hmac;
use rand::{CryptoRng, RngCore};
use hmac::{KeyInit, SimpleHmac};
use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption};
use zeroize::Zeroize;
@@ -49,7 +49,7 @@ pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
use crate::key_exchange::shared::{derive_keys, generate_ke1, generate_nonce, transcript};
use crate::keypair::{KeyPair, PrivateKey, PublicKey};
use crate::opaque::Identifiers;
use crate::serialization::{SliceExt, UpdateExt};
use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// The SIGMA-I key exchange implementation
///
@@ -95,7 +95,7 @@ pub trait SignatureProtocol {
/// The signature.
type Signature: Clone + Zeroize;
/// Length of a serialized [`Signature`](Self::Signature).
type SignatureLen: ArrayLength<u8>;
type SignatureLen: ArrayLength;
/// The state required to run the verification. This is used to cache the
/// pre-hash for curves that support that, otherwise the [`Message`] to
/// verify is stored via [`CachedMessage`].
@@ -111,7 +111,7 @@ pub trait SignatureProtocol {
/// The returned [`VerifyState`](Self::VerifyState) will be passed to
/// [`verify()`](Self::verify) and must contain the necessary
/// information to verify the incoming signature.
fn sign<R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>(
fn sign<R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk,
rng: &mut R,
message: &Message<CS, KE>,
@@ -202,8 +202,9 @@ pub struct Ke2State<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> {
pub struct Ke2Message<SIG: SignatureProtocol, KE: Group, KEH: Hash>
where
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{
server_nonce: GenericArray<u8, NonceLen>,
#[derive_where(skip(Zeroize))]
@@ -223,37 +224,42 @@ where
)]
#[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; SIG::Signature)]
pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser> {
pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser>
where
<KEH as OutputSizeUser>::OutputSize: ArrayLength,
{
signature: SIG::Signature,
mac: Output<KEH>,
}
impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash> KeyExchange for SigmaI<SIG, KE, KEH>
impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash + BlockSizeUser> KeyExchange
for SigmaI<SIG, KE, KEH>
where
KE::Sk: DiffieHellman<KE>,
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{
type Group = SIG::Group;
type Hash = KEH;
type KE1State = Ke1State<KE>;
type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
type KE1Message = Ke1Message<KE>;
type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'a, CS, KE>;
type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>;
type KE2BuilderInput<CS: CipherSuite> = (SIG::Signature, SIG::VerifyState<CS, KE>);
type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
type KE2Message = Ke2Message<SIG, KE, KEH>;
type KE3Message = Ke3Message<SIG, KEH>;
fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
generate_ke1(rng)
}
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>(
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -287,13 +293,13 @@ where
&transcript_hasher.finalize(),
)?;
let mut server_mac =
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
.map_err(|_| InternalError::HmacError)?;
server_mac.update_iter(identifiers.server.iter());
let server_mac = server_mac.finalize().into_bytes();
let mut client_mac =
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
.map_err(|_| InternalError::HmacError)?;
client_mac.update_iter(identifiers.client.iter());
let client_mac = client_mac.finalize().into_bytes();
@@ -331,7 +337,7 @@ where
&builder.transcript
}
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>,
rng: &mut R,
server_s_sk: &PrivateKey<Self::Group>,
@@ -363,7 +369,7 @@ where
})
}
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -397,8 +403,8 @@ where
&transcript_hasher.finalize(),
)?;
let mut server_mac =
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
.map_err(|_| InternalError::HmacError)?;
server_mac.update_iter(identifiers.server.iter());
let server_mac = server_mac.finalize().into_bytes();
@@ -406,8 +412,8 @@ where
.then_some(())
.ok_or(ProtocolError::InvalidLoginError)?;
let mut client_mac =
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
.map_err(|_| InternalError::HmacError)?;
client_mac.update_iter(identifiers.client.iter());
let client_mac = client_mac.finalize().into_bytes();
@@ -481,13 +487,14 @@ where
impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Deserialize for Ke2State<CS, SIG, KE>
where
SIG::VerifyState<CS, KE>: Deserialize,
OutputSize<KeHash<CS>>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
client_s_pk: PublicKey::deserialize_take(input)?,
session_key: input.take_array("session key")?,
verify_state: SIG::VerifyState::deserialize_take(input)?,
expected_mac: input.take_array("expected mac")?,
session_key: input.take_array("session key")?.into_ha0_4(),
verify_state: SIG::VerifyState::<CS, KE>::deserialize_take(input)?,
expected_mac: input.take_array("expected mac")?.into_ha0_4(),
})
}
}
@@ -502,37 +509,44 @@ type VerifyStateLen<CS, SIG: SignatureProtocol, KE> = <SIG::VerifyState<CS, KE>
impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Serialize for Ke2State<CS, SIG, KE>
where
SIG::VerifyState<CS, KE>: Serialize,
OutputSize<KeHash<CS>>: ArrayLength,
// Ke2State: ((SigPk + Hash) + VerifyState) + Hash
<SIG::Group as Group>::PkLen: Add<OutputSize<KeHash<CS>>>,
Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>:
ArrayLength<u8> + Add<VerifyStateLen<CS, SIG, KE>>,
ArrayLength + Add<VerifyStateLen<CS, SIG, KE>>,
Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>:
ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>,
Ke2StateLen<CS, SIG, KE>: ArrayLength<u8>,
ArrayLength + Add<OutputSize<KeHash<CS>>>,
Ke2StateLen<CS, SIG, KE>: ArrayLength,
{
type Len = Ke2StateLen<CS, SIG, KE>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_s_pk
.serialize()
.concat(self.session_key.clone())
.concat(self.verify_state.serialize())
.concat(self.expected_mac.clone())
Concat::concat(
Concat::concat(
Concat::concat(
self.client_s_pk.serialize(),
GenericArray::from_slice(self.session_key.as_slice()).clone(),
),
self.verify_state.serialize(),
),
GenericArray::from_slice(self.expected_mac.as_slice()).clone(),
)
}
}
impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Deserialize for Ke2Message<SIG, KE, KEH>
where
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
server_nonce: input.take_array("server nonce")?,
server_e_pk: PublicKey::deserialize_take(input)?,
signature: SIG::deserialize_take_signature(input)?,
mac: input.take_array("mac")?,
mac: input.take_array("mac")?.into_ha0_4(),
})
}
}
@@ -540,34 +554,36 @@ where
impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Serialize for Ke2Message<SIG, KE, KEH>
where
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
// Ke2Message: ((Nonce + KePk) + Signature) + Hash
NonceLen: Add<KE::PkLen>,
Sum<NonceLen, KE::PkLen>: ArrayLength<u8> + Add<SIG::SignatureLen>,
Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength<u8> + Add<OutputSize<KEH>>,
Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength<u8>,
Sum<NonceLen, KE::PkLen>: ArrayLength + Add<SIG::SignatureLen>,
Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength + Add<OutputSize<KEH>>,
Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength,
{
type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.server_nonce
.concat(self.server_e_pk.serialize())
.concat(SIG::serialize_signature(&self.signature))
.concat(self.mac.clone())
.cat(self.server_e_pk.serialize())
.cat(SIG::serialize_signature(&self.signature))
.cat(GenericArray::from_slice(self.mac.as_slice()).clone())
}
}
impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH>
where
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
signature: SIG::deserialize_take_signature(input)?,
mac: input.take_array("mac")?,
mac: input.take_array("mac")?.into_ha0_4(),
})
}
}
@@ -575,15 +591,19 @@ where
impl<SIG: SignatureProtocol, KEH: Hash> Serialize for Ke3Message<SIG, KEH>
where
KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
// Ke2Message: Signature + Hash
SIG::SignatureLen: Add<OutputSize<KEH>>,
Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength<u8>,
Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength,
{
type Len = Sum<SIG::SignatureLen, OutputSize<KEH>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
SIG::serialize_signature(&self.signature).concat(self.mac.clone())
Concat::concat(
SIG::serialize_signature(&self.signature),
GenericArray::from_slice(self.mac.as_slice()).clone(),
)
}
}
+7 -7
View File
@@ -12,7 +12,7 @@
use core::marker::PhantomData;
use generic_array::GenericArray;
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use zeroize::Zeroize;
use self::implementation::PureEddsaImpl;
@@ -34,7 +34,7 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
type SignatureLen = G::SignatureLen;
type VerifyState<CS: CipherSuite, KE: Group> = CachedMessage<CS, KE>;
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>(
fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &G::Sk,
_: &mut R,
message: &Message<CS, KE>,
@@ -51,13 +51,13 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
G::verify(pk, message_builder, state, signature)
}
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
G::deserialize_take_signature(bytes)
}
fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> {
G::serialize_signature(signature)
}
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
G::deserialize_take_signature(bytes)
}
}
pub(in super::super) mod implementation {
@@ -67,7 +67,7 @@ pub(in super::super) mod implementation {
pub trait PureEddsaImpl: Group {
type Signature: Clone + Zeroize;
type SignatureLen: ArrayLength<u8>;
type SignatureLen: ArrayLength;
fn sign<CS: CipherSuite, KE: Group>(
sk: &Self::Sk,
+11 -5
View File
@@ -16,24 +16,30 @@ use crate::serialization::SliceExt;
/// Pre-hash of the message to be verified.
#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
#[derive_where(Copy; <H::OutputSize as ArrayLength<u8>>::ArrayType)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "")
)]
#[allow(dead_code)]
pub struct PreHash<H: OutputSizeUser>(pub Output<H>);
impl<H: OutputSizeUser> Deserialize for PreHash<H> {
impl<H: OutputSizeUser> Deserialize for PreHash<H>
where
H::OutputSize: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self(input.take_array("pre-hash")?))
Ok(Self(input.take_array("pre-hash")?.into_ha0_4()))
}
}
impl<H: OutputSizeUser> Serialize for PreHash<H> {
impl<H: OutputSizeUser> Serialize for PreHash<H>
where
H::OutputSize: ArrayLength,
{
type Len = H::OutputSize;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone()
GenericArray::from_slice(self.0.as_slice()).clone()
}
}
+62 -47
View File
@@ -12,12 +12,11 @@ use core::marker::PhantomData;
use core::ops::Add;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use digest::{Output, OutputSizeUser};
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption};
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -34,7 +33,7 @@ use crate::key_exchange::shared::{self, NonceLen};
pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
use crate::keypair::{PrivateKey, PublicKey};
use crate::opaque::Identifiers;
use crate::serialization::SliceExt;
use crate::serialization::{ConcatExt, SliceExt};
////////////////////////////
// High-level API Structs //
@@ -79,8 +78,9 @@ pub struct Ke2State<H: OutputSizeUser> {
pub struct Ke2Builder<G: Group, H: Hash>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
server_nonce: GenericArray<u8, NonceLen>,
transcript_hasher: H,
@@ -104,8 +104,9 @@ where
pub struct Ke2Message<G: Group, H: Hash>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
pub(super) server_nonce: GenericArray<u8, NonceLen>,
#[derive_where(skip(Zeroize))]
@@ -123,8 +124,9 @@ where
pub struct Ke3Message<H: Hash>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
pub(super) mac: Output<H>,
}
@@ -138,8 +140,9 @@ impl<G: Group + 'static, H: Hash> KeyExchange for TripleDh<G, H>
where
G::Sk: DiffieHellman<G>,
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
type Group = G;
type Hash = H;
@@ -153,13 +156,13 @@ where
type KE2Message = Ke2Message<G, H>;
type KE3Message = Ke3Message<H>;
fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
shared::generate_ke1(rng)
}
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>(
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -201,7 +204,7 @@ where
&builder.client_e_pk
}
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>,
_: &mut R,
server_s_sk: &PrivateKey<G>,
@@ -247,7 +250,7 @@ where
})
}
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
_: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -319,13 +322,14 @@ where
impl<H: Hash> Deserialize for Ke2State<H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
session_key: input.take_array("session key")?,
expected_mac: input.take_array("expected mac")?,
session_key: input.take_array("session key")?.into_ha0_4(),
expected_mac: input.take_array("expected mac")?.into_ha0_4(),
})
}
}
@@ -333,26 +337,32 @@ where
impl<H: Hash> Serialize for Ke2State<H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
// Ke2State: Hash + Hash
OutputSize<H>: Add<OutputSize<H>>,
Sum<OutputSize<H>, OutputSize<H>>: ArrayLength<u8>,
Sum<OutputSize<H>, OutputSize<H>>: ArrayLength,
{
type Len = Sum<OutputSize<H>, OutputSize<H>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.session_key.clone().concat(self.expected_mac.clone())
let sk: GenericArray<u8, OutputSize<H>> =
GenericArray::from_slice(self.session_key.as_slice()).clone();
let mac: GenericArray<u8, OutputSize<H>> =
GenericArray::from_slice(self.expected_mac.as_slice()).clone();
sk.cat(mac)
}
}
/// TODO: implement via derive after hash crates get `Zeroize` support in
/// `digest` v11.
/// TODO: implement via derive after `Hash` gets `Zeroize` support.
impl<G: Group, H: Hash> Drop for Ke2Builder<G, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
fn drop(&mut self) {
let Self {
@@ -365,7 +375,7 @@ where
} = self;
server_nonce.zeroize();
transcript_hasher.reset();
digest::Reset::reset(transcript_hasher);
shared_secret_1.zeroize();
shared_secret_3.zeroize();
}
@@ -374,22 +384,24 @@ where
impl<G: Group, H: Hash> ZeroizeOnDrop for Ke2Builder<G, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
}
impl<G: Group, H: Hash> Deserialize for Ke2Message<G, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
server_nonce: input.take_array("server nonce")?,
server_e_pk: PublicKey::deserialize_take(input)?,
mac: input.take_array("mac")?,
mac: input.take_array("mac")?.into_ha0_4(),
})
}
}
@@ -397,31 +409,33 @@ where
impl<H: Hash, G: Group> Serialize for Ke2Message<G, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
// Ke2Message: (Nonce + KePk) + Hash
NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>,
Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
{
type Len = Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.server_nonce
.concat(self.server_e_pk.serialize())
.concat(self.mac.clone())
.cat(self.server_e_pk.serialize())
.cat(GenericArray::from_slice(self.mac.as_slice()).clone())
}
}
impl<H: Hash> Deserialize for Ke3Message<H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
mac: bytes.take_array("mac")?,
mac: bytes.take_array("mac")?.into_ha0_4(),
})
}
}
@@ -429,12 +443,13 @@ where
impl<H: Hash> Serialize for Ke3Message<H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{
type Len = OutputSize<H>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.mac.clone()
GenericArray::from_slice(self.mac.as_slice()).clone()
}
}
+96 -69
View File
@@ -23,18 +23,18 @@ use core::marker::PhantomData;
use core::ops::Add;
use derive_where::derive_where;
use digest::core_api::BlockSizeUser;
use digest::{Digest, Output};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use digest::Output;
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use generic_array::typenum::{Cmp, IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray};
use hybrid_array::ArraySize;
#[allow(deprecated)]
use ml_kem::ExpandedKeyEncoding;
use ml_kem::kem::{
Ciphertext as MlKemCiphertext, Decapsulate, Encapsulate, Kem as MlKemTrait, KeyExport,
KeySizeUser, TryKeyInit,
};
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption};
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -50,7 +50,7 @@ use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::Group;
use crate::keypair::{PrivateKey, PublicKey};
use crate::opaque::Identifiers;
use crate::serialization::SliceExt;
use crate::serialization::{ConcatExt, SliceExt};
/// Adapter trait that augments the `ml-kem` core traits with the metadata
/// required by OPAQUE (e.g. fixed lengths and serialization hooks).
@@ -62,16 +62,16 @@ pub trait KemCoreWrapper {
type DecapsulationKey: Clone + ZeroizeOnDrop;
/// Length (in bytes) of the serialized public key.
type EncapsulationKeyLen: ArrayLength<u8>;
type EncapsulationKeyLen: ArrayLength + ArraySize;
/// Length (in bytes) of the serialized secret key.
type DecapsulationKeyLen: ArrayLength<u8>;
type DecapsulationKeyLen: ArrayLength + ArraySize;
/// Length (in bytes) of the encapsulated ciphertext.
type CiphertextLen: ArrayLength<u8>;
type CiphertextLen: ArrayLength + ArraySize;
/// Length (in bytes) of the shared secret output by the KEM.
type SharedSecretLen: ArrayLength<u8>;
type SharedSecretLen: ArrayLength + ArraySize;
/// Generates a fresh KEM key pair.
fn generate<R: RngCore + CryptoRng>(
fn generate<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError>;
@@ -98,7 +98,7 @@ pub trait KemCoreWrapper {
/// Encapsulates to the given public key, returning the ciphertext and
/// shared secret.
#[allow(clippy::type_complexity)]
fn encapsulate<R: RngCore + CryptoRng>(
fn encapsulate<R: Rng + CryptoRng>(
key: &Self::EncapsulationKey,
rng: &mut R,
) -> Result<
@@ -120,7 +120,7 @@ pub trait KemCoreWrapper {
/// which is required by `ml-kem 0.3.x`.
struct RngCompat<'a, R>(&'a mut R);
impl<R: RngCore> rand_core_10::TryRng for RngCompat<'_, R> {
impl<R: Rng> rand_core::TryRng for RngCompat<'_, R> {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
@@ -137,7 +137,7 @@ impl<R: RngCore> rand_core_10::TryRng for RngCompat<'_, R> {
}
}
impl<R: RngCore + CryptoRng> rand_core_10::TryCryptoRng for RngCompat<'_, R> {}
impl<R: Rng + CryptoRng> rand_core::TryCryptoRng for RngCompat<'_, R> {}
type RcEncapsulationKeyLen<K> = <<K as MlKemTrait>::EncapsulationKey as KeySizeUser>::KeySize;
#[allow(deprecated)]
@@ -152,10 +152,10 @@ where
K: MlKemTrait,
K::EncapsulationKey: Encapsulate<Kem = K> + KeyExport + TryKeyInit + Clone,
K::DecapsulationKey: Decapsulate<Kem = K> + ExpandedKeyEncoding + Clone + ZeroizeOnDrop,
RcEncapsulationKeyLen<K>: ArrayLength<u8>,
RcDecapsulationKeyLen<K>: ArrayLength<u8>,
RcCiphertextLen<K>: ArrayLength<u8>,
RcSharedSecretLen<K>: ArrayLength<u8>,
RcEncapsulationKeyLen<K>: ArrayLength + ArraySize,
RcDecapsulationKeyLen<K>: ArrayLength + ArraySize,
RcCiphertextLen<K>: ArrayLength + ArraySize,
RcSharedSecretLen<K>: ArrayLength + ArraySize,
{
type EncapsulationKey = K::EncapsulationKey;
type DecapsulationKey = K::DecapsulationKey;
@@ -164,7 +164,7 @@ where
type CiphertextLen = RcCiphertextLen<K>;
type SharedSecretLen = RcSharedSecretLen<K>;
fn generate<R: RngCore + CryptoRng>(
fn generate<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> {
Ok(K::generate_keypair_from_rng(&mut RngCompat(rng)))
@@ -173,7 +173,7 @@ where
fn serialize_encapsulation_key(
key: &Self::EncapsulationKey,
) -> GenericArray<u8, Self::EncapsulationKeyLen> {
GenericArray::clone_from_slice(key.to_bytes().as_slice())
GenericArray::from_slice(key.to_bytes().as_slice()).clone()
}
fn deserialize_encapsulation_key(
@@ -189,7 +189,7 @@ where
fn serialize_decapsulation_key(
key: &Self::DecapsulationKey,
) -> GenericArray<u8, Self::DecapsulationKeyLen> {
GenericArray::clone_from_slice(key.to_expanded_bytes().as_slice())
GenericArray::from_slice(key.to_expanded_bytes().as_slice()).clone()
}
fn deserialize_decapsulation_key(
@@ -203,7 +203,7 @@ where
.map_err(|_| ProtocolError::SerializationError)
}
fn encapsulate<R: RngCore + CryptoRng>(
fn encapsulate<R: Rng + CryptoRng>(
key: &Self::EncapsulationKey,
rng: &mut R,
) -> Result<
@@ -215,8 +215,8 @@ where
> {
let (ciphertext, shared) = key.encapsulate_with_rng(&mut RngCompat(rng));
Ok((
GenericArray::clone_from_slice(ciphertext.as_slice()),
GenericArray::clone_from_slice(shared.as_slice()),
GenericArray::from_slice(ciphertext.as_slice()).clone(),
GenericArray::from_slice(shared.as_slice()).clone(),
))
}
@@ -227,7 +227,7 @@ where
let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice())
.map_err(|_| ProtocolError::SerializationError)?;
let shared = key.decapsulate(&ciphertext);
Ok(GenericArray::clone_from_slice(shared.as_slice()))
Ok(GenericArray::from_slice(shared.as_slice()).clone())
}
}
/// Triple Diffie-Hellman-style key exchange that offloads the second hop to a
@@ -281,8 +281,10 @@ pub struct KemKe1Message<G: Group, K: KemCoreWrapper> {
pub struct KemKe2State<K: KemCoreWrapper, H: Hash>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{
base_state: super::tripledh::Ke2State<H>,
kem_encapsulation_key: GenericArray<u8, K::EncapsulationKeyLen>,
@@ -295,8 +297,10 @@ where
pub struct KemKe2Builder<G: Group, H: Hash, K: KemCoreWrapper>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{
server_nonce: GenericArray<u8, NonceLen>,
transcript_hasher: H,
@@ -323,8 +327,10 @@ where
pub struct KemKe2Message<G: Group, H: Hash, K: KemCoreWrapper>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{
dh_message: super::tripledh::Ke2Message<G, H>,
kem_ciphertext: GenericArray<u8, K::CiphertextLen>,
@@ -338,13 +344,15 @@ where
G: Group,
H: Hash,
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper,
{
fn drop(&mut self) {
self.server_nonce.zeroize();
self.transcript_hasher.reset();
digest::Digest::reset(&mut self.transcript_hasher);
self.shared_secret_1.zeroize();
self.shared_secret_3.zeroize();
self.kem_shared_secret.zeroize();
@@ -357,8 +365,10 @@ where
G: Group,
H: Hash,
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper,
{
}
@@ -369,11 +379,13 @@ where
G::Sk: shared::DiffieHellman<G>,
H: Hash,
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper,
NonceLen: Add<K::EncapsulationKeyLen>,
Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength<u8>,
Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength,
{
type Group = G;
type Hash = H;
@@ -390,7 +402,7 @@ where
type KE2Message = KemKe2Message<G, H, K>;
type KE3Message = KemKe3Message<H>;
fn generate_ke1<R: RngCore + CryptoRng>(
fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
let base = super::tripledh::TripleDh::<G, H>::generate_ke1(rng)?;
@@ -409,7 +421,7 @@ where
})
}
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>(
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -440,8 +452,11 @@ where
let (kem_ciphertext, kem_shared_secret) = K::encapsulate(&encapsulation_key, rng)?;
let mut transcript_hasher = transcript_hasher;
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice());
transcript_hasher.update(kem_ciphertext.as_slice());
digest::Digest::update(
&mut transcript_hasher,
ke1_message.kem_encapsulation_key.as_slice(),
);
digest::Digest::update(&mut transcript_hasher, kem_ciphertext.as_slice());
Ok(KemKe2Builder {
server_nonce,
@@ -462,7 +477,7 @@ where
(&builder.client_e_pk, &builder.kem_encapsulation_key)
}
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>,
_: &mut R,
server_s_sk: &PrivateKey<G>,
@@ -516,7 +531,7 @@ where
})
}
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>(
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
_rng: &mut R,
credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message,
@@ -537,8 +552,14 @@ where
ke2_message.dh_message.server_nonce,
&ke2_message.dh_message.server_e_pk.serialize(),
);
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice());
transcript_hasher.update(ke2_message.kem_ciphertext.as_slice());
digest::Digest::update(
&mut transcript_hasher,
ke1_message.kem_encapsulation_key.as_slice(),
);
digest::Digest::update(
&mut transcript_hasher,
ke2_message.kem_ciphertext.as_slice(),
);
let shared_secret_1 = ke1_state
.dh_state
@@ -606,14 +627,14 @@ impl<G: Group, K: KemCoreWrapper> Serialize for KemKe1State<G, K>
where
Ke1State<G>: Serialize,
<Ke1State<G> as Serialize>::Len: Add<K::DecapsulationKeyLen>,
Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength<u8>,
Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength,
{
type Len = Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_state
.serialize()
.concat(K::serialize_decapsulation_key(&self.kem_decapsulation_key))
.cat(K::serialize_decapsulation_key(&self.kem_decapsulation_key))
}
}
@@ -630,22 +651,24 @@ impl<G: Group, K: KemCoreWrapper> Serialize for KemKe1Message<G, K>
where
Ke1Message<G>: Serialize,
<Ke1Message<G> as Serialize>::Len: Add<K::EncapsulationKeyLen>,
Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength<u8>,
Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength,
{
type Len = Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_message
.serialize()
.concat(self.kem_encapsulation_key.clone())
.cat(self.kem_encapsulation_key.clone())
}
}
impl<K: KemCoreWrapper, H: Hash> Deserialize for KemKe2State<K, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
@@ -659,16 +682,18 @@ where
impl<K: KemCoreWrapper, H: Hash> Serialize for KemKe2State<K, H>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
super::tripledh::Ke2State<H>: Serialize,
<super::tripledh::Ke2State<H> as Serialize>::Len: Add<K::EncapsulationKeyLen>,
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>:
ArrayLength<u8> + Add<K::CiphertextLen>,
ArrayLength + Add<K::CiphertextLen>,
Sum<
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
K::CiphertextLen,
>: ArrayLength<u8>,
>: ArrayLength,
{
type Len = Sum<
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
@@ -678,16 +703,18 @@ where
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.base_state
.serialize()
.concat(self.kem_encapsulation_key.clone())
.concat(self.server_kem_ciphertext.clone())
.cat(self.kem_encapsulation_key.clone())
.cat(self.server_kem_ciphertext.clone())
}
}
impl<G: Group, H: Hash, K: KemCoreWrapper> Deserialize for KemKe2Message<G, H, K>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
@@ -700,21 +727,21 @@ where
impl<G: Group, H: Hash, K: KemCoreWrapper> Serialize for KemKe2Message<G, H, K>
where
H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>,
Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
super::tripledh::Ke2Message<G, H>: Serialize,
<super::tripledh::Ke2Message<G, H> as Serialize>::Len: Add<K::CiphertextLen>,
<<super::tripledh::Ke2Message<G, H> as Serialize>::Len as Add<K::CiphertextLen>>::Output:
ArrayLength<u8>,
ArrayLength,
{
type Len = Sum<<super::tripledh::Ke2Message<G, H> as Serialize>::Len, K::CiphertextLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_message
.serialize()
.concat(self.kem_ciphertext.clone())
self.dh_message.serialize().cat(self.kem_ciphertext.clone())
}
}
+43 -35
View File
@@ -13,7 +13,7 @@
use derive_where::derive_where;
use digest::{Output, OutputSizeUser};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use rand::{CryptoRng, Rng};
use crate::ciphersuite::CipherSuite;
use crate::errors::ProtocolError;
@@ -32,11 +32,7 @@ use crate::serialization::SliceExt;
))
)]
#[derive_where(Clone)]
#[derive_where(Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk, SK)]
// `NonZeroScalar` doesn't implement `Debug`.
// TODO: remove after `elliptic-curve` bump to v0.14.
#[cfg_attr(not(test), derive_where(Debug; G::Pk, SK))]
#[cfg_attr(test, derive_where(Debug), derive_where(skip_inner(Debug)))]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk, SK)]
pub struct KeyPair<G: Group, SK: Clone = PrivateKey<G>> {
pk: PublicKey<G>,
sk: SK,
@@ -60,7 +56,7 @@ impl<G: Group, SK: Clone> KeyPair<G, SK> {
}
impl<G: Group> KeyPair<G> {
pub(crate) fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
pub(crate) fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let sk = G::random_sk(rng);
let pk = G::public_key(&sk);
Self {
@@ -70,7 +66,7 @@ impl<G: Group> KeyPair<G> {
}
/// Generating a random key pair given a cryptographic rng
pub(crate) fn derive_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
pub(crate) fn derive_random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let mut scalar_bytes = GenericArray::<_, <G as Group>::SkLen>::default();
rng.fill_bytes(&mut scalar_bytes);
let sk = G::derive_scalar(scalar_bytes).unwrap();
@@ -133,7 +129,7 @@ where
impl<G: Group> PrivateKey<G> {
/// Private-key signing implementation
pub(crate) fn sign<
R: CryptoRng + RngCore,
R: CryptoRng + Rng,
CS: CipherSuite,
SIG: SignatureProtocol<Group = G>,
KE: Group,
@@ -152,7 +148,7 @@ pub trait PrivateKeySerialization<G: Group>: Clone {
/// Custom error type that can be passed down to `ProtocolError::Custom`
type Error;
/// Serialization size in bytes.
type Len: ArrayLength<u8>;
type Len: ArrayLength;
/// Serialization into bytes
fn serialize_key_pair(key_pair: &KeyPair<G, Self>) -> GenericArray<u8, Self::Len>;
@@ -242,7 +238,7 @@ pub struct OprfSeed<H: OutputSizeUser>(pub(crate) Output<H>);
/// Will be called with `E` being [`PrivateKeySerialization::Error`].
pub trait OprfSeedSerialization<H, E>: Sized {
/// Serialization size in bytes.
type Len: ArrayLength<u8>;
type Len: ArrayLength;
/// Serialization into bytes
fn serialize(&self) -> GenericArray<u8, Self::Len>;
@@ -253,18 +249,22 @@ pub trait OprfSeedSerialization<H, E>: Sized {
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError<E>>;
}
impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H> {
impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H>
where
H::OutputSize: ArrayLength,
{
type Len = H::OutputSize;
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone()
GenericArray::from_slice(self.0.as_slice()).clone()
}
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError<E>> {
Ok(Self(
input
.take_array("OPRF seed")
.map_err(ProtocolError::into_custom)?,
.map_err(ProtocolError::into_custom)?
.into_ha0_4(),
))
}
}
@@ -275,7 +275,11 @@ impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H> {
//////////////////////////
#[cfg(test)]
impl<G: Group> KeyPair<G> {
impl<G: Group> KeyPair<G>
where
G::Pk: core::fmt::Debug,
G::Sk: core::fmt::Debug,
{
/// Test-only strategy returning a proptest Strategy based on
/// [`Self::derive_random`]
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
@@ -297,9 +301,6 @@ impl<G: Group> KeyPair<G> {
#[cfg(test)]
mod tests {
use hkdf::Hkdf;
use rand::rngs::OsRng;
use super::*;
use crate::ciphersuite::{KeGroup, OprfHash};
use crate::{
@@ -309,6 +310,9 @@ mod tests {
ServerLoginParameters, ServerLoginStartResult, ServerRegistration,
ServerRegistrationStartResult, ServerSetup,
};
use hkdf::Hkdf;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
macro_rules! test {
($mod:ident, $point:ty) => {
@@ -323,7 +327,7 @@ mod tests {
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
let pk = kp.public();
let sk = kp.private();
prop_assert_eq!(&sk.public_key(), pk);
prop_assert_eq!(sk.public_key().serialize(), pk.serialize());
}
#[test]
@@ -380,23 +384,24 @@ mod tests {
#[test]
fn remote_key() {
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut OsRng));
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut UnwrapErr(SysRng)));
let pk = sk.public_key();
let sk = RemoteKey(sk);
let keypair = KeyPair::new(sk, pk);
let server_setup =
ServerSetup::<Default, RemoteKey>::new_with_key_pair(&mut OsRng, keypair);
ServerSetup::<Default, RemoteKey>::new_with_key_pair(&mut UnwrapErr(SysRng), keypair);
let ClientRegistrationStartResult {
message,
state: client,
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
} = ClientRegistration::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes())
.unwrap();
let ServerRegistrationStartResult { message, .. } =
ServerRegistration::start(&server_setup, message, &[]).unwrap();
let ClientRegistrationFinishResult { message, .. } = client
.finish(
&mut OsRng,
&mut UnwrapErr(SysRng),
PASSWORD.as_bytes(),
message,
ClientRegistrationFinishParameters::default(),
@@ -407,9 +412,9 @@ mod tests {
let ClientLoginStartResult {
message,
state: client,
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
} = ClientLogin::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()).unwrap();
let builder = ServerLogin::builder(
&mut OsRng,
&mut UnwrapErr(SysRng),
&server_setup,
Some(file),
message,
@@ -425,7 +430,7 @@ mod tests {
} = builder.build(shared_secret).unwrap();
let ClientLoginFinishResult { message, .. } = client
.finish(
&mut OsRng,
&mut UnwrapErr(SysRng),
PASSWORD.as_bytes(),
message,
ClientLoginFinishParameters::default(),
@@ -438,22 +443,25 @@ mod tests {
#[test]
fn remote_seed() {
let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default());
OsRng.fill_bytes(&mut oprf_seed.0);
let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default().into_ha0_4());
UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0);
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut OsRng));
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut UnwrapErr(SysRng)));
let pk = sk.public_key();
let sk = RemoteKey(sk);
let keypair = KeyPair::new(sk, pk);
let server_setup = ServerSetup::<Default, _, _>::new_with_key_pair_and_seed(
&mut OsRng, keypair, oprf_seed,
&mut UnwrapErr(SysRng),
keypair,
oprf_seed,
);
let ClientRegistrationStartResult {
message,
state: client,
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
} = ClientRegistration::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes())
.unwrap();
let km = server_setup.key_material_info(&[]);
let mut ikm = GenericArray::default();
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
@@ -464,7 +472,7 @@ mod tests {
ServerRegistration::start_with_key_material(&server_setup, ikm, message).unwrap();
let ClientRegistrationFinishResult { message, .. } = client
.finish(
&mut OsRng,
&mut UnwrapErr(SysRng),
PASSWORD.as_bytes(),
message,
ClientRegistrationFinishParameters::default(),
@@ -475,7 +483,7 @@ mod tests {
let ClientLoginStartResult {
message,
state: client,
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
} = ClientLogin::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()).unwrap();
let km = server_setup.key_material_info(&[]);
let mut ikm = GenericArray::default();
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
@@ -483,7 +491,7 @@ mod tests {
.expand_multi_info(&km.info, &mut ikm)
.unwrap();
let builder = ServerLogin::builder_with_key_material(
&mut OsRng,
&mut UnwrapErr(SysRng),
&server_setup,
ikm,
Some(file),
@@ -499,7 +507,7 @@ mod tests {
} = builder.build(shared_secret).unwrap();
let ClientLoginFinishResult { message, .. } = client
.finish(
&mut OsRng,
&mut UnwrapErr(SysRng),
PASSWORD.as_bytes(),
message,
ClientLoginFinishParameters::default(),
+3 -3
View File
@@ -15,7 +15,7 @@ use crate::errors::InternalError;
/// Used for the key stretching function in OPAQUE
pub trait Ksf: Default {
/// Computes the key stretching function
fn hash<L: ArrayLength<u8>>(
fn hash<L: ArrayLength>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError>;
@@ -26,7 +26,7 @@ pub trait Ksf: Default {
pub struct Identity;
impl Ksf for Identity {
fn hash<L: ArrayLength<u8>>(
fn hash<L: ArrayLength>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> {
@@ -36,7 +36,7 @@ impl Ksf for Identity {
#[cfg(feature = "argon2")]
impl Ksf for argon2::Argon2<'_> {
fn hash<L: ArrayLength<u8>>(
fn hash<L: ArrayLength>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> {
+242 -221
View File
@@ -27,14 +27,14 @@
//!
//! We will use the following choices in this example:
//! ```ignore
//! use opaque_ke::CipherSuite;
//! use opaque_vx::CipherSuite;
//!
//! struct Default;
//!
//! impl CipherSuite for Default {
//! type OprfCs = opaque_ke::Ristretto255;
//! type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! type Ksf = opaque_ke::ksf::Identity;
//! type OprfCs = opaque_vx::Ristretto255;
//! type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! type Ksf = opaque_vx::ksf::Identity;
//! }
//! ```
//! See [examples/simple_login.rs](https://github.com/facebook/opaque-ke/blob/main/examples/simple_login.rs)
@@ -50,26 +50,27 @@
//! To set up the protocol, the server begins by creating a `ServerSetup`
//! object:
//! ```
//! # use opaque_ke::errors::ProtocolError;
//! # use opaque_ke::CipherSuite;
//! # use opaque_ke::ServerSetup;
//! # use opaque_vx::errors::ProtocolError;
//! # use opaque_vx::CipherSuite;
//! # use opaque_vx::ServerSetup;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! use rand::RngCore;
//! use rand::rngs::OsRng;
//! use rand::Rng;
//! use rand::rngs::SysRng;
//! use rand_core::UnwrapErr;
//!
//! let mut rng = OsRng;
//! let mut rng = UnwrapErr(SysRng);
//! let server_setup = ServerSetup::<Default>::new(&mut rng);
//! # Ok::<(), ProtocolError>(())
//! ```
@@ -103,30 +104,31 @@
//! [`ClientRegistration`] which must be persisted on the client for the final
//! step of client registration.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ServerRegistration,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! use opaque_ke::ClientRegistration;
//! use rand::RngCore;
//! use rand::rngs::OsRng;
//! use opaque_vx::ClientRegistration;
//! use rand::Rng;
//! use rand::rngs::SysRng;
//! use rand_core::UnwrapErr;
//!
//! let mut client_rng = OsRng;
//! let mut client_rng = UnwrapErr(SysRng);
//! let client_registration_start_result =
//! ClientRegistration::<Default>::start(&mut client_rng, b"password")?;
//! # Ok::<(), ProtocolError>(())
@@ -140,35 +142,36 @@
//! [`ServerRegistrationStartResult`], which consists of a
//! [`RegistrationResponse`] to be returned to the client.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration,
//! # ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! use opaque_ke::ServerRegistration;
//! use opaque_vx::ServerRegistration;
//!
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! let server_registration_start_result = ServerRegistration::<Default>::start(
//! &server_setup,
@@ -188,35 +191,36 @@
//! which can be used optionally as described in the [Export Key](#export-key)
//! section.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! use opaque_ke::ClientRegistrationFinishParameters;
//! use opaque_vx::ClientRegistrationFinishParameters;
//!
//! let client_registration_finish_result = client_registration_start_result.state.finish(
//! &mut client_rng,
@@ -236,32 +240,33 @@
//! [`ServerRegistration::serialize`] to store the password file for use during
//! the login protocol.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -287,29 +292,30 @@
//! [`CredentialRequest`] to be sent to the server, and a [`ClientLogin`] which
//! must be persisted on the client for the final step of client login.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! use opaque_ke::ClientLogin;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! use opaque_vx::ClientLogin;
//!
//! let mut client_rng = OsRng;
//! let mut client_rng = UnwrapErr(SysRng);
//! let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"password")?;
//! # Ok::<(), ProtocolError>(())
//! ```
@@ -323,32 +329,33 @@
//! a [`ServerLogin`] which must be persisted on the server for the final step
//! of login.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -357,10 +364,10 @@
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! use opaque_ke::{ServerLogin, ServerLoginParameters};
//! use opaque_vx::{ServerLogin, ServerLoginParameters};
//!
//! let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
//! let mut server_rng = OsRng;
//! let mut server_rng = UnwrapErr(SysRng);
//! let server_login_start_result = ServerLogin::start(
//! &mut server_rng,
//! &server_setup,
@@ -393,32 +400,33 @@
//! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key)
//! which will match the server's session key upon a successful login.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -433,7 +441,7 @@
//! # )?;
//! # let server_login_start_result =
//! # ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"[email protected]", ServerLoginParameters::default())?;
//! use opaque_ke::ClientLoginFinishParameters;
//! use opaque_vx::ClientLoginFinishParameters;
//!
//! let client_login_finish_result = client_login_start_result.state.finish(
//! &mut client_rng,
@@ -450,32 +458,33 @@
//! to produce an output consisting of the `session_key` sequence of bytes which
//! will match the client's session key upon a successful login.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -547,32 +556,33 @@
//! registration (with the `server_s_pk` field of
//! [`ClientRegistrationFinishResult`]) matches this field during login.
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! // During registration, the client obtains a ClientRegistrationFinishResult with
@@ -644,32 +654,33 @@
//! You can access the export key from the `export_key` field of
//! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`].
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! // During registration...
@@ -727,20 +738,20 @@
//! the ciphersuite as follows:
//!
//! ```ignore
//! use opaque_ke::CipherSuite;
//! use opaque_vx::CipherSuite;
//!
//! struct KemSuite;
//!
//! impl CipherSuite for KemSuite {
//! type OprfCs = opaque_ke::Ristretto255;
//! type KeyExchange = opaque_ke::TripleDhKem<opaque_ke::Ristretto255, sha2::Sha512, opaque_ke::ml_kem::MlKem768>;
//! type Ksf = opaque_ke::ksf::Identity;
//! type OprfCs = opaque_vx::Ristretto255;
//! type KeyExchange = opaque_vx::TripleDhKem<opaque_vx::Ristretto255, sha2::Sha512, opaque_vx::ml_kem::MlKem768>;
//! type Ksf = opaque_vx::ksf::Identity;
//! }
//! ```
//!
//! ## Custom Identifiers
//!
//! Typically when applications use OPAQUE to authenticate a client to a server,
//! Typically, when applications use OPAQUE to authenticate a client to a server,
//! the client has a registered username which is sent to the server to identify
//! the corresponding password file established during registration. This
//! username may or may not coincide with the server-side identifier; however,
@@ -756,32 +767,33 @@
//! [`ClientRegistrationFinishParameters`] in [Client Registration
//! Finish](#client-registration-finish):
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! let client_registration_finish_result = client_registration_start_result.state.finish(
@@ -802,32 +814,33 @@
//! The same identifiers must also be supplied using [`ServerLoginParameters`]
//! in [Server Login Start](#server-login-start):
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -836,9 +849,9 @@
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # use opaque_ke::{ServerLogin, ServerLoginParameters};
//! # use opaque_vx::{ServerLogin, ServerLoginParameters};
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! let server_login_start_result = ServerLogin::start(
//! &mut server_rng,
//! &server_setup,
@@ -859,32 +872,33 @@
//! as well as [`ClientLoginFinishParameters`] in [Client Login
//! Finish](#client-login-finish):
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -918,32 +932,33 @@
//! and in [`ServerLoginParameters`] in [Server Login
//! Finish](#server-login-finish):
//! ```
//! # use opaque_ke::{
//! # use opaque_vx::{
//! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity,
//! # };
//! # use opaque_ke::CipherSuite;
//! # use opaque_vx::CipherSuite;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # use rand::{rngs::OsRng, RngCore};
//! # let mut client_rng = OsRng;
//! # use rand::{rngs::SysRng, Rng};
//! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng,
//! # b"password",
//! # )?;
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -981,7 +996,7 @@
//!
//! A key exchange protocol typically allows for the specifying of shared
//! "context" information between the two parties before the exchange is
//! complete, so as to bind the integrity of application-specific data or
//! complete, to bind the integrity of application-specific data or
//! configuration parameters to the security of the key exchange. During the
//! login phase, the client and server can specify this context using:
//! - In [Server Login Start](#server-login-start), where the server can
@@ -1008,21 +1023,23 @@
//! exposing the bytes of the private key to this library.
//! ```
//! # use generic_array::{GenericArray, typenum::U0};
//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::OsRng;
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::SysRng;
//! # use rand_core::UnwrapErr;
//!
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[derive(Debug, thiserror::Error)]
//! # #[error("test error")]
@@ -1034,9 +1051,9 @@
//! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
//! # }
//! # }
//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerSetup};
//! use opaque_ke::keypair::{KeyPair, PrivateKeySerialization};
//! use opaque_ke::errors::ProtocolError;
//! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerSetup};
//! use opaque_vx::keypair::{KeyPair, PrivateKeySerialization};
//! use opaque_vx::errors::ProtocolError;
//!
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
//! impl PrivateKeySerialization<Ristretto255> for YourRemoteKey {
@@ -1052,24 +1069,24 @@
//! }
//! }
//!
//! # let sk = Ristretto255::random_sk(&mut OsRng);
//! # let sk = Ristretto255::random_sk(&mut UnwrapErr(SysRng));
//! # let pk = Ristretto255::public_key(&sk);
//! # let pk = Ristretto255::serialize_pk(&pk);
//! # let public_key = PublicKey::deserialize(&pk).unwrap();
//! # let remote_key = YourRemoteKey(sk);
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! let keypair = KeyPair::new(remote_key, public_key);
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key_pair(&mut server_rng, keypair);
//!
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut OsRng,
//! # &mut UnwrapErr(SysRng),
//! # b"password",
//! # )?;
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut UnwrapErr(SysRng), b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
//! # let client_login_start_result = ClientLogin::<Default>::start(
//! # &mut OsRng,
//! # &mut UnwrapErr(SysRng),
//! # b"password",
//! # )?;
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
@@ -1102,24 +1119,26 @@
//! # use digest::Output;
//! # use generic_array::{GenericArray, typenum::U0};
//! # use hkdf::Hkdf;
//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::OsRng;
//! # use rand::RngCore;
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::SysRng;
//! # use rand::Rng;
//! # use rand_core::UnwrapErr;
//!
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # type Hash = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Hash;
//! # type OprfGroup = <<Default as CipherSuite>::OprfCs as voprf::CipherSuite>::Group;
//! # struct Default;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_vx::ksf::Identity;
//! # }
//! # #[derive(Debug, thiserror::Error)]
//! # #[error("test error")]
@@ -1143,9 +1162,9 @@
//! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
//! # }
//! # }
//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup};
//! use opaque_ke::keypair::{KeyPair, OprfSeedSerialization};
//! use opaque_ke::errors::ProtocolError;
//! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup};
//! use opaque_vx::keypair::{KeyPair, OprfSeedSerialization};
//! use opaque_vx::errors::ProtocolError;
//!
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
//! impl OprfSeedSerialization<sha2::Sha512, YourRemoteSecretsError> for YourRemoteSeed {
@@ -1160,20 +1179,20 @@
//! }
//! }
//!
//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default());
//! # OsRng.fill_bytes(&mut oprf_seed.0);
//! # let sk = Ristretto255::random_sk(&mut OsRng);
//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default().into_ha0_4());
//! # UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0);
//! # let sk = Ristretto255::random_sk(&mut UnwrapErr(SysRng));
//! # let pk = Ristretto255::public_key(&sk);
//! # let pk = Ristretto255::serialize_pk(&pk);
//! # let public_key = PublicKey::deserialize(&pk).unwrap();
//! # let remote_key = YourRemoteKey(sk);
//! # let mut server_rng = OsRng;
//! # let mut server_rng = UnwrapErr(SysRng);
//! let keypair = KeyPair::new(remote_key, public_key);
//! let server_setup = ServerSetup::<Default, YourRemoteKey, YourRemoteSeed>::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed);
//!
//! // Incoming registration ...
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut OsRng,
//! # &mut UnwrapErr(SysRng),
//! # b"password",
//! # )?;
//!
@@ -1189,12 +1208,12 @@
//! )?;
//!
//! // Finish registration ...
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut UnwrapErr(SysRng), b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//!
//! // Incoming login ...
//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
//! # let client_login_start_result = ClientLogin::<Default>::start(
//! # &mut OsRng,
//! # &mut UnwrapErr(SysRng),
//! # b"password",
//! # )?;
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
@@ -1231,20 +1250,20 @@
//! can be used.
//! ```
//! # use generic_array::GenericArray;
//! use opaque_ke::ksf::Ksf;
//! use opaque_vx::ksf::Ksf;
//!
//! #[derive(Default)]
//! struct CustomKsf(scrypt::Params);
//!
//! // The Ksf trait must be implemented to be used in the ciphersuite.
//! impl Ksf for CustomKsf {
//! fn hash<L: generic_array::ArrayLength<u8>>(
//! fn hash<L: generic_array::ArrayLength>(
//! &self,
//! input: GenericArray<u8, L>,
//! ) -> Result<GenericArray<u8, L>, opaque_ke::errors::InternalError> {
//! ) -> Result<GenericArray<u8, L>, opaque_vx::errors::InternalError> {
//! let mut output = GenericArray::<u8, L>::default();
//! scrypt::scrypt(&input, &[], &self.0, &mut output)
//! .map_err(|_| opaque_ke::errors::InternalError::KsfError)?;
//! .map_err(|_| opaque_vx::errors::InternalError::KsfError)?;
//!
//! Ok(output)
//! }
@@ -1255,37 +1274,38 @@
//! used by the KSF during registration and login. This can be especially
//! helpful if the `Ksf` trait is already implemented.
//! ```
//! # use opaque_ke::CipherSuite;
//! # use opaque_ke::ClientRegistration;
//! # use opaque_ke::ClientRegistrationFinishParameters;
//! # use opaque_ke::ServerSetup;
//! # use opaque_ke::errors::ProtocolError;
//! # use rand::rngs::OsRng;
//! # use rand::RngCore;
//! # use opaque_vx::CipherSuite;
//! # use opaque_vx::ClientRegistration;
//! # use opaque_vx::ClientRegistrationFinishParameters;
//! # use opaque_vx::ServerSetup;
//! # use opaque_vx::errors::ProtocolError;
//! # use rand::rngs::SysRng;
//! # use rand::Rng;
//! # use rand_core::UnwrapErr;
//! # use std::default::Default;
//! # #[cfg(feature = "argon2")]
//! # {
//! # struct DefaultCipherSuite;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
//! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = argon2::Argon2<'static>;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = argon2::Argon2<'static>;
//! # }
//! #
//! # let password = b"password";
//! # let mut rng = OsRng;
//! # let mut rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
//! # let mut client_rng = OsRng;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result =
//! # ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?;
//! # use opaque_ke::ServerRegistration;
//! # use opaque_vx::ServerRegistration;
//! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
//! # &server_setup,
//! # client_registration_start_result.message,
@@ -1384,6 +1404,7 @@ mod tests;
#[cfg(feature = "argon2")]
pub use argon2;
pub use generic_array;
pub use hybrid_array;
#[cfg(feature = "kem")]
pub use ml_kem;
pub use rand;
+57 -39
View File
@@ -15,7 +15,8 @@ use digest::Output;
use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, Unsigned};
use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore};
use hybrid_array::Array;
use rand::{CryptoRng, Rng};
use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen};
use zeroize::Zeroizing;
@@ -50,7 +51,7 @@ use crate::serialization::SliceExt;
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)]
pub struct RegistrationRequest<CS: CipherSuite> {
/// blinded password information
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
}
/// The answer sent by the server to the user, upon reception of the
@@ -64,10 +65,11 @@ pub struct RegistrationRequest<CS: CipherSuite> {
))
)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <KeGroup<CS> as Group>::Pk)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <KeGroup<CS> as Group>::Pk
)]
pub struct RegistrationResponse<CS: CipherSuite> {
/// The server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
/// Server's static public key
pub(crate) server_s_pk: PublicKey<KeGroup<CS>>,
}
@@ -111,7 +113,7 @@ pub struct RegistrationUpload<CS: CipherSuite> {
<CS::KeyExchange as KeyExchange>::KE1Message,
)]
pub struct CredentialRequest<CS: CipherSuite> {
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message,
}
@@ -136,7 +138,7 @@ pub struct CredentialRequest<CS: CipherSuite> {
)]
pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> {
pub(crate) server_s_sk: SK,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>,
pub(crate) masked_response: MaskedResponse<CS>,
#[cfg(test)]
@@ -184,12 +186,12 @@ impl<CS: CipherSuite, SK: Clone> ServerLoginBuilder<'_, CS, SK> {
#[derive_where(Clone)]
#[derive_where(
Debug, Eq, Hash, PartialEq;
voprf::EvaluationElement<CS::OprfCs>,
EvaluationElement<CS::OprfCs>,
<CS::KeyExchange as KeyExchange>::KE2Message,
)]
pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
pub(crate) masking_nonce: GenericArray<u8, NonceLen>,
pub(crate) masked_response: MaskedResponse<CS>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange>::KE2Message,
@@ -225,19 +227,19 @@ pub type RegistrationRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Grou
impl<CS: CipherSuite> RegistrationRequest<CS> {
/// Only used for testing purposes
#[cfg(test)]
pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> {
pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
self.blinded_element.clone()
}
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, RegistrationRequestLen<CS>> {
pub fn serialize(&self) -> Array<u8, RegistrationRequestLen<CS>> {
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value())
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
blinded_element: voprf::BlindedElement::deserialize(input)?,
blinded_element: BlindedElement::deserialize(input)?,
})
}
}
@@ -251,11 +253,14 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
where
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen> + ArrayLength,
RegistrationResponseLen<CS>: ArrayLength,
{
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value())
.concat(self.server_s_pk.serialize())
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
self.evaluation_element.value(),
));
elem.concat(self.server_s_pk.serialize())
}
/// Deserialization from bytes
@@ -277,7 +282,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
beta: <OprfGroup<CS> as voprf::Group>::Elem,
) -> Self {
Self {
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
evaluation_element: EvaluationElement::from_value_unchecked(beta),
server_s_pk: self.server_s_pk.clone(),
}
}
@@ -294,26 +299,29 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
{
self.client_s_pk
.serialize()
.concat(self.masking_key.clone())
.concat(self.envelope.serialize())
Concat::concat(
Concat::concat(
self.client_s_pk.serialize(),
GenericArray::from_slice(self.masking_key.as_slice()).clone(),
),
self.envelope.serialize(),
)
}
/// Deserialization from bytes
pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
client_s_pk: PublicKey::deserialize_take(&mut input)?,
masking_key: input.take_array("masking key")?,
masking_key: input.take_array("masking key")?.into_ha0_4(),
envelope: Envelope::deserialize_take(&mut input)?,
})
}
// Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, OS: Clone>(
pub(crate) fn dummy<R: Rng + CryptoRng, SK: Clone, OS: Clone>(
rng: &mut R,
server_setup: &ServerSetup<CS, SK, OS>,
) -> Self {
@@ -338,11 +346,14 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
where
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
// CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>> + ArrayLength,
CredentialRequestLen<CS>: ArrayLength,
{
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value())
.concat(self.ke1_message.serialize())
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
self.blinded_element.value(),
));
elem.concat(self.ke1_message.serialize())
}
/// Deserialization from bytes
@@ -372,7 +383,7 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
/// Only used for testing purposes
#[cfg(test)]
pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> {
pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
self.blinded_element.clone()
}
}
@@ -390,18 +401,25 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
where
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen> + ArrayLength,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value())
.concat(self.masking_nonce)
.concat(self.masked_response.serialize())
.concat(self.ke2_message.serialize())
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
self.evaluation_element.value(),
));
Concat::concat(
Concat::concat(
Concat::concat(elem, self.masking_nonce),
self.masked_response.serialize(),
),
self.ke2_message.serialize(),
)
}
/// Deserialization from bytes
@@ -410,7 +428,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize,
{
let evaluation_element = EvaluationElement::deserialize(input)?;
input = &input[voprf::EvaluationElementLen::<CS::OprfCs>::USIZE..];
input = &input[EvaluationElementLen::<CS::OprfCs>::USIZE..];
Ok(Self {
evaluation_element,
@@ -438,7 +456,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
beta: <OprfGroup<CS> as voprf::Group>::Elem,
) -> Self {
Self {
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
evaluation_element: EvaluationElement::from_value_unchecked(beta),
masking_nonce: self.masking_nonce,
masked_response: self.masked_response.clone(),
ke2_message: self.ke2_message.clone(),
+74 -66
View File
@@ -8,15 +8,14 @@
//! Provides the main OPAQUE API
use core::ops::{Add, Deref};
use core::ops::Add;
use derive_where::derive_where;
use digest::Output;
use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, Unsigned};
use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract};
use rand::{CryptoRng, RngCore};
use hkdf::Hkdf;
use hkdf::SimpleHkdfExtract as HkdfExtract;
use rand::{CryptoRng, Rng};
use subtle::{Choice, ConstantTimeEq, CtOption};
use voprf::{BlindedElement, Group as _, OprfClient, OprfClientLen};
use zeroize::Zeroizing;
@@ -36,7 +35,7 @@ use crate::keypair::{
};
use crate::ksf::Ksf;
use crate::messages::{CredentialRequestLen, RegistrationUploadLen};
use crate::serialization::{GenericArrayExt, SliceExt};
use crate::serialization::{ConcatExt, GenericArrayExt, SliceExt};
use crate::{
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload, ServerLoginBuilder,
@@ -70,7 +69,8 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
))
)]
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <KeGroup<CS> as Group>::Pk, <KeGroup<CS> as Group>::Sk, SK, OS)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <KeGroup<CS> as Group>::Pk, <KeGroup<CS> as Group>::Sk, SK, OS
)]
pub struct ServerSetup<
CS: CipherSuite,
SK: Clone = PrivateKey<KeGroup<CS>>,
@@ -94,8 +94,8 @@ pub struct ServerSetup<
voprf::BlindedElement<CS::OprfCs>,
)]
pub struct ClientRegistration<CS: CipherSuite> {
pub(crate) oprf_client: voprf::OprfClient<CS::OprfCs>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
pub(crate) oprf_client: OprfClient<CS::OprfCs>,
pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
}
/// The state elements the server holds to record a registration
@@ -130,7 +130,7 @@ pub struct ServerRegistration<CS: CipherSuite>(pub(crate) RegistrationUpload<CS>
CredentialRequest<CS>,
)]
pub struct ClientLogin<CS: CipherSuite> {
pub(crate) oprf_client: voprf::OprfClient<CS::OprfCs>,
pub(crate) oprf_client: OprfClient<CS::OprfCs>,
pub(crate) ke1_state: <CS::KeyExchange as KeyExchange>::KE1State,
pub(crate) credential_request: CredentialRequest<CS>,
}
@@ -160,7 +160,7 @@ pub struct ServerLogin<CS: CipherSuite> {
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<KeGroup<CS>>> {
/// Generate a new instance of server setup
pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
pub fn new<R: CryptoRng + Rng>(rng: &mut R) -> Self {
let keypair = KeyPair::random(rng);
Self::new_with_key_pair(rng, keypair)
}
@@ -179,7 +179,7 @@ impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
/// This function should not be used to restore a previously-existing
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
/// [`ServerSetup::deserialize`] for this purpose.
pub fn new_with_key_pair_and_seed<R: CryptoRng + RngCore>(
pub fn new_with_key_pair_and_seed<R: CryptoRng + Rng>(
rng: &mut R,
keypair: KeyPair<KeGroup<CS>, SK>,
oprf_seed: OS,
@@ -211,13 +211,13 @@ impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
// ServerSetup: Hash + KeSk + KePk
OS::Len: Add<SK::Len>,
Sum<OS::Len, SK::Len>: ArrayLength<u8> + Add<<KeGroup<CS> as Group>::PkLen>,
ServerSetupLen<CS, SK, OS>: ArrayLength<u8>,
Sum<OS::Len, SK::Len>: ArrayLength + Add<<KeGroup<CS> as Group>::PkLen>,
ServerSetupLen<CS, SK, OS>: ArrayLength,
{
self.oprf_seed
.serialize()
.concat(SK::serialize_key_pair(&self.keypair))
.concat(self.dummy_pk.serialize())
.cat(SK::serialize_key_pair(&self.keypair))
.cat(self.dummy_pk.serialize())
}
/// Deserialization from bytes
@@ -246,11 +246,11 @@ impl<CS: CipherSuite, SK: Clone> ServerSetup<CS, SK> {
/// This function should not be used to restore a previously-existing
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
/// [`ServerSetup::deserialize`] for this purpose.
pub fn new_with_key_pair<R: CryptoRng + RngCore>(
pub fn new_with_key_pair<R: CryptoRng + Rng>(
rng: &mut R,
keypair: KeyPair<KeGroup<CS>, SK>,
) -> Self {
let mut oprf_seed = GenericArray::default();
let mut oprf_seed = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut oprf_seed);
Self::new_with_key_pair_and_seed(rng, keypair, OprfSeed(oprf_seed))
@@ -282,12 +282,13 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
pub fn serialize(&self) -> GenericArray<u8, ClientRegistrationLen<CS>>
where
// ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
<OprfGroup<CS> as voprf::Group>::ScalarLen:
Add<<OprfGroup<CS> as voprf::Group>::ElemLen> + ArrayLength,
<OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
ClientRegistrationLen<CS>: ArrayLength,
{
self.oprf_client
.serialize()
.concat(self.blinded_element.serialize())
GenericArray::from_ha0_4(self.oprf_client.serialize())
.cat(GenericArray::from_ha0_4(self.blinded_element.serialize()))
}
/// Deserialization from bytes
@@ -305,7 +306,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// Returns an initial "blinded" request to send to the server, as well as a
/// [`ClientRegistration`]
pub fn start<R: RngCore + CryptoRng>(
pub fn start<R: Rng + CryptoRng>(
blinding_factor_rng: &mut R,
password: &[u8],
) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> {
@@ -325,7 +326,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// "Unblinds" the server's answer and returns a final message containing
/// cryptographic identifiers, to be sent to the server on setup
/// finalization
pub fn finish<R: CryptoRng + RngCore>(
pub fn finish<R: CryptoRng + Rng>(
self,
rng: &mut R,
password: &[u8],
@@ -357,7 +358,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
let result = Envelope::<CS>::seal(
rng,
randomized_pwd_hasher,
&randomized_pwd_hasher,
&registration_response.server_s_pk,
params.identifiers,
)?;
@@ -390,8 +391,8 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
{
self.0.serialize()
@@ -449,7 +450,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
}
// Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, S: Clone>(
pub(crate) fn dummy<R: Rng + CryptoRng, SK: Clone, S: Clone>(
rng: &mut R,
server_setup: &ServerSetup<CS, SK, S>,
) -> Self {
@@ -470,18 +471,17 @@ impl<CS: CipherSuite> ClientLogin<CS> {
// CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength,
{
self.oprf_client
.serialize()
.concat(self.credential_request.serialize())
.concat(self.ke1_state.serialize())
GenericArray::from_ha0_4(self.oprf_client.serialize())
.cat(self.credential_request.serialize())
.cat(self.ke1_state.serialize())
}
/// Deserialization from bytes
@@ -504,7 +504,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
impl<CS: CipherSuite> ClientLogin<CS> {
/// Returns an initial "blinded" password request to send to the server, as
/// well as a [`ClientLogin`]
pub fn start<R: RngCore + CryptoRng>(
pub fn start<R: Rng + CryptoRng>(
rng: &mut R,
password: &[u8],
) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
@@ -528,7 +528,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// "Unblinds" the server's answer and returns the opened assets from the
/// server
pub fn finish<R: CryptoRng + RngCore>(
pub fn finish<R: CryptoRng + Rng>(
self,
rng: &mut R,
password: &[u8],
@@ -570,7 +570,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
let opened_envelope = envelope
.open(
randomized_pwd_hasher,
&randomized_pwd_hasher,
server_s_pk.clone(),
params.identifiers,
)
@@ -641,7 +641,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
///
/// See [`ServerLogin::start()`] for the regular path. Or
/// [`ServerLogin::builder()`] with just a remote private key.
pub fn builder_with_key_material<'a, R: RngCore + CryptoRng, SK: Clone, OS: Clone>(
pub fn builder_with_key_material<'a, R: Rng + CryptoRng, SK: Clone, OS: Clone>(
rng: &mut R,
server_setup: &ServerSetup<CS, SK, OS>,
key_material: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
@@ -668,7 +668,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let masked_response = mask_response(
&record.0.masking_key,
masking_nonce.as_slice(),
&masking_nonce,
server_s_pk,
&record.0.envelope,
)?;
@@ -715,7 +715,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// Create a [`ServerLoginBuilder`] to use with a remote private key.
///
/// See [`ServerLogin::start()`] for the regular path.
pub fn builder<'a, R: RngCore + CryptoRng, SK: Clone>(
pub fn builder<'a, R: Rng + CryptoRng, SK: Clone>(
rng: &mut R,
server_setup: &ServerSetup<CS, SK>,
password_file: Option<ServerRegistration<CS>>,
@@ -747,7 +747,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let credential_response = CredentialResponse {
evaluation_element: builder.evaluation_element.clone(),
masking_nonce: *builder.masking_nonce.deref(),
masking_nonce: *builder.masking_nonce,
masked_response: builder.masked_response.clone(),
ke2_message: result.message,
};
@@ -762,13 +762,13 @@ impl<CS: CipherSuite> ServerLogin<CS> {
#[cfg(test)]
server_mac_key: result.km2,
#[cfg(test)]
oprf_key: builder.oprf_key.deref().clone(),
oprf_key: (*builder.oprf_key).clone(),
})
}
/// From the client's "blinded" password, returns a challenge to be sent
/// back to the client, as well as a [`ServerLogin`]
pub fn start<R: RngCore + CryptoRng>(
pub fn start<R: Rng + CryptoRng>(
rng: &mut R,
server_setup: &ServerSetup<CS>,
password_file: Option<ServerRegistration<CS>>,
@@ -1004,21 +1004,22 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
#[allow(clippy::type_complexity)]
fn get_password_derived_key<CS: CipherSuite>(
input: &[u8],
oprf_client: voprf::OprfClient<CS::OprfCs>,
oprf_client: OprfClient<CS::OprfCs>,
evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
ksf: Option<&CS::Ksf>,
) -> Result<(Output<OprfHash<CS>>, Hkdf<OprfHash<CS>>), ProtocolError> {
) -> Result<(Output<OprfHash<CS>>, hkdf::SimpleHkdf<OprfHash<CS>>), ProtocolError> {
let oprf_output = oprf_client.finalize(input, &evaluation_element)?;
let oprf_ga = GenericArray::from_ha0_4(oprf_output.clone());
let hardened_output = if let Some(ksf) = ksf {
ksf.hash(oprf_output.clone())
ksf.hash(oprf_ga.clone())
} else {
CS::Ksf::default().hash(oprf_output.clone())
CS::Ksf::default().hash(oprf_ga.clone())
}
.map_err(ProtocolError::from)?;
let mut hkdf = HkdfExtract::<OprfHash<CS>>::new(None);
hkdf.input_ikm(&oprf_output);
hkdf.input_ikm(&oprf_ga);
hkdf.input_ikm(&hardened_output);
Ok(hkdf.finalize())
}
@@ -1039,13 +1040,9 @@ fn oprf_key_material<CS: CipherSuite>(
fn oprf_key_from_key_material<CS: CipherSuite>(
input: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
) -> Result<GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, InternalError> {
Ok(OprfGroup::<CS>::serialize_scalar(voprf::derive_key::<
CS::OprfCs,
>(
input.as_slice(),
&GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
voprf::Mode::Oprf,
)?))
Ok(GenericArray::from_ha0_4(OprfGroup::<CS>::serialize_scalar(
voprf::derive_key::<CS::OprfCs>(&input, STR_OPAQUE_DERIVE_KEY_PAIR, voprf::Mode::Oprf)?,
)))
}
#[cfg_attr(
@@ -1066,19 +1063,28 @@ pub(crate) type MaskedResponseLen<CS: CipherSuite> =
impl<CS: CipherSuite> MaskedResponse<CS> {
pub(crate) fn serialize(&self) -> GenericArray<u8, MaskedResponseLen<CS>> {
self.nonce.concat_ext(&self.hash).concat(self.pk.clone())
}
let hash_ga: &GenericArray<u8, OutputSize<OprfHash<CS>>> =
GenericArray::from_slice(self.hash.as_slice());
self.nonce.concat_ext(hash_ga).cat(self.pk.clone())
}
pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self {
nonce: bytes.take_array("masked nonce")?,
hash: bytes.take_array("masked hash")?,
hash: bytes
.take_array::<OutputSize<OprfHash<CS>>>("masked hash")?
.into_ha0_4(),
pk: bytes.take_array("masked public key")?,
})
}
pub(crate) fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
[self.nonce.as_slice(), &self.hash, &self.pk].into_iter()
[
self.nonce.as_slice(),
self.hash.as_slice(),
self.pk.as_slice(),
]
.into_iter()
}
}
@@ -1105,7 +1111,9 @@ fn mask_response<CS: CipherSuite>(
*x1 ^= x2
}
MaskedResponse::deserialize_take(&mut (xor_pad.as_slice()))
let mut slice: &[u8] = &xor_pad;
MaskedResponse::deserialize_take(&mut (slice))
}
fn unmask_response<CS: CipherSuite>(
@@ -1124,7 +1132,7 @@ fn unmask_response<CS: CipherSuite>(
*x1 ^= x2
}
let mut xor_pad = xor_pad.as_slice();
let mut xor_pad: &[u8] = xor_pad.as_ref();
let server_s_pk =
PublicKey::deserialize_take(&mut xor_pad).map_err(|_| ProtocolError::SerializationError)?;
let envelope = Envelope::deserialize_take(&mut xor_pad)?;
@@ -1135,12 +1143,12 @@ fn unmask_response<CS: CipherSuite>(
/// Internal function for computing the blind result by calling the voprf
/// library. Note that for tests, we use the deterministic blinding in order to
/// be able to set the blinding factor directly from the passed-in rng.
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
fn blind<CS: CipherSuite, R: Rng + CryptoRng>(
rng: &mut R,
password: &[u8],
) -> Result<voprf::OprfClientBlindResult<CS::OprfCs>, voprf::Error> {
#[cfg(not(test))]
let result = voprf::OprfClient::blind(password, rng)?;
let result = OprfClient::blind(password, rng)?;
#[cfg(test)]
let result = {
@@ -1152,7 +1160,7 @@ fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
break scalar;
}
};
voprf::OprfClient::deterministic_blind_unchecked(password, blind)?
OprfClient::deterministic_blind_unchecked(password, blind)?
};
Ok(result)
+33 -17
View File
@@ -8,18 +8,16 @@
use core::ops::Add;
use crate::errors::ProtocolError;
use digest::Update;
use generic_array::sequence::Concat;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use crate::errors::ProtocolError;
use hybrid_array::{Array, ArraySize};
// Corresponds to the I2OSP() function from RFC8017
pub(crate) fn i2osp<L: ArrayLength<u8>>(
input: usize,
) -> Result<GenericArray<u8, L>, ProtocolError> {
const SIZEOF_USIZE: usize = core::mem::size_of::<usize>();
pub(crate) fn i2osp<L: ArrayLength>(input: usize) -> Result<GenericArray<u8, L>, ProtocolError> {
const SIZEOF_USIZE: usize = size_of::<usize>();
// Make sure input fits in output.
if (SIZEOF_USIZE as u32 - input.leading_zeros() / 8) > L::U32 {
@@ -35,12 +33,12 @@ pub(crate) fn i2osp<L: ArrayLength<u8>>(
// Corresponds to the OS2IP() function from RFC8017
#[cfg(test)]
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, ProtocolError> {
if input.len() > core::mem::size_of::<usize>() {
if input.len() > size_of::<usize>() {
return Err(ProtocolError::SerializationError);
}
let mut output_array = [0u8; core::mem::size_of::<usize>()];
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
let mut output_array = [0u8; size_of::<usize>()];
output_array[size_of::<usize>() - input.len()..].copy_from_slice(input);
Ok(usize::from_be_bytes(output_array))
}
@@ -69,14 +67,14 @@ impl<T: Update> UpdateExt for T {
}
pub(crate) trait SliceExt {
fn take_array<L: ArrayLength<u8>>(
fn take_array<L: ArrayLength + ArraySize>(
self: &mut &Self,
name: &'static str,
) -> Result<GenericArray<u8, L>, ProtocolError>;
}
impl SliceExt for [u8] {
fn take_array<L: ArrayLength<u8>>(
fn take_array<L: ArrayLength + ArraySize>(
self: &mut &Self,
name: &'static str,
) -> Result<GenericArray<u8, L>, ProtocolError> {
@@ -90,23 +88,24 @@ impl SliceExt for [u8] {
let (front, back) = self.split_at(L::USIZE);
*self = back;
Ok(GenericArray::clone_from_slice(front))
let arr: Array<u8, L> = Array::try_from(front).unwrap();
Ok(GenericArray::from(arr))
}
}
pub(crate) trait GenericArrayExt<O: ArrayLength<u8>> {
type Output: ArrayLength<u8>;
pub(crate) trait GenericArrayExt<O: ArrayLength> {
type Output: ArrayLength;
/// This allows us to concat two [`GenericArray`]s but with `where` bounds
/// `Other + Self`. Because sometimes `Self + Other` doesn't imply the
/// bounds and we have to add them to every call.
/// bounds, and we have to add them to every call.
fn concat_ext(&self, rest: &GenericArray<u8, O>) -> GenericArray<u8, Self::Output>;
}
impl<L: ArrayLength<u8>, O: ArrayLength<u8>> GenericArrayExt<O> for GenericArray<u8, L>
impl<L: ArrayLength, O: ArrayLength> GenericArrayExt<O> for GenericArray<u8, L>
where
O: Add<L>,
Sum<O, L>: ArrayLength<u8>,
Sum<O, L>: ArrayLength,
{
type Output = Sum<O, L>;
@@ -119,6 +118,23 @@ where
}
}
pub(crate) trait ConcatExt<N: ArrayLength>: Sized {
fn cat<M: ArrayLength>(self, other: GenericArray<u8, M>) -> GenericArray<u8, Sum<N, M>>
where
N: Add<M>,
Sum<N, M>: ArrayLength;
}
impl<N: ArrayLength> ConcatExt<N> for GenericArray<u8, N> {
fn cat<M: ArrayLength>(self, other: GenericArray<u8, M>) -> GenericArray<u8, Sum<N, M>>
where
N: Add<M>,
Sum<N, M>: ArrayLength,
{
Concat::concat(self, other)
}
}
#[cfg(test)]
mod tests;
+62 -63
View File
@@ -15,8 +15,9 @@ use generic_array::ArrayLength;
use generic_array::typenum::{Sum, Unsigned};
use proptest::collection::vec;
use proptest::prelude::*;
use rand::RngCore;
use rand::rngs::OsRng;
use rand::Rng;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use voprf::Group as _;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
@@ -41,7 +42,7 @@ struct TripleDhRistretto255;
impl CipherSuite for TripleDhRistretto255 {
type OprfCs = Ristretto255;
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity;
type Ksf = ksf::Identity;
}
#[cfg(all(feature = "ristretto255", feature = "curve25519"))]
@@ -51,31 +52,31 @@ struct TripleDhCurve25519;
impl CipherSuite for TripleDhCurve25519 {
type OprfCs = Ristretto255;
type KeyExchange = TripleDh<Curve25519, sha2::Sha512>;
type Ksf = crate::ksf::Identity;
type Ksf = ksf::Identity;
}
struct TripleDhP256;
impl CipherSuite for TripleDhP256 {
type OprfCs = ::p256::NistP256;
type KeyExchange = TripleDh<::p256::NistP256, sha2::Sha256>;
type Ksf = crate::ksf::Identity;
type OprfCs = p256::NistP256;
type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
type Ksf = ksf::Identity;
}
struct TripleDhP384;
impl CipherSuite for TripleDhP384 {
type OprfCs = ::p384::NistP384;
type KeyExchange = TripleDh<::p384::NistP384, sha2::Sha384>;
type Ksf = crate::ksf::Identity;
type OprfCs = p384::NistP384;
type KeyExchange = TripleDh<p384::NistP384, sha2::Sha384>;
type Ksf = ksf::Identity;
}
struct TripleDhP521;
impl CipherSuite for TripleDhP521 {
type OprfCs = ::p521::NistP521;
type KeyExchange = TripleDh<::p521::NistP521, sha2::Sha512>;
type Ksf = crate::ksf::Identity;
type OprfCs = p521::NistP521;
type KeyExchange = TripleDh<p521::NistP521, sha2::Sha512>;
type Ksf = ksf::Identity;
}
#[cfg(feature = "ecdsa")]
@@ -83,10 +84,9 @@ struct SigmaIP256;
#[cfg(feature = "ecdsa")]
impl CipherSuite for SigmaIP256 {
type OprfCs = ::p256::NistP256;
type KeyExchange =
SigmaI<Ecdsa<::p256::NistP256, sha2::Sha256>, ::p256::NistP256, sha2::Sha256>;
type Ksf = crate::ksf::Identity;
type OprfCs = p256::NistP256;
type KeyExchange = SigmaI<Ecdsa<p256::NistP256, sha2::Sha256>, p256::NistP256, sha2::Sha256>;
type Ksf = ksf::Identity;
}
#[cfg(feature = "ecdsa")]
@@ -94,10 +94,9 @@ struct SigmaIP384;
#[cfg(feature = "ecdsa")]
impl CipherSuite for SigmaIP384 {
type OprfCs = ::p384::NistP384;
type KeyExchange =
SigmaI<Ecdsa<::p384::NistP384, sha2::Sha384>, ::p384::NistP384, sha2::Sha384>;
type Ksf = crate::ksf::Identity;
type OprfCs = p384::NistP384;
type KeyExchange = SigmaI<Ecdsa<p384::NistP384, sha2::Sha384>, p384::NistP384, sha2::Sha384>;
type Ksf = ksf::Identity;
}
#[cfg(all(feature = "ristretto255", feature = "ed25519",))]
@@ -107,7 +106,7 @@ struct SigmaIEd25519;
impl CipherSuite for SigmaIEd25519 {
type OprfCs = Ristretto255;
type KeyExchange = SigmaI<PureEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity;
type Ksf = ksf::Identity;
}
#[cfg(all(feature = "ristretto255", feature = "ed25519"))]
@@ -117,19 +116,19 @@ struct SigmaIEd25519Ph;
impl CipherSuite for SigmaIEd25519Ph {
type OprfCs = Ristretto255;
type KeyExchange = SigmaI<HashEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity;
type Ksf = ksf::Identity;
}
#[cfg(feature = "ecdsa")]
fn random_point<CS: CipherSuite>() -> <KeGroup<CS> as Group>::Pk {
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let sk = KeGroup::<CS>::random_sk(&mut rng);
KeGroup::<CS>::public_key(&sk)
}
fn random_element<CS: CipherSuite>() -> <OprfGroup<CS> as voprf::Group>::Elem {
let mut rng = OsRng;
let scalar = OprfGroup::<CS>::random_scalar(&mut rng);
let mut rng = UnwrapErr(SysRng);
let scalar = OprfGroup::<CS>::random_scalar(&mut rng).unwrap();
OprfGroup::<CS>::base_elem() * &scalar
}
@@ -139,10 +138,10 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
where
// ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
ClientRegistrationLen<CS>: ArrayLength,
{
let pw = b"hunter2";
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let blind_result = &voprf::OprfClient::<CS::OprfCs>::blind(pw, &mut rng)?;
@@ -186,12 +185,12 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
{
// If we don't have envelope and client_pk, the server registration just
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let mut masking_key = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut masking_key);
@@ -287,11 +286,11 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
where
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
RegistrationResponseLen<CS>: ArrayLength,
{
let elem = random_element::<CS>();
let beta_bytes = OprfGroup::<CS>::serialize_elem(elem);
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let pubkey_bytes = skp.public().serialize();
@@ -345,10 +344,10 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let pubkey_bytes = skp.public().serialize();
@@ -360,15 +359,15 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
let mut masking_key = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut masking_key);
let randomized_pwd_hasher = hkdf::Hkdf::new(None, &key);
let randomized_pwd_hasher = hkdf::SimpleHkdf::<OprfHash<CS>>::new(None, &key);
let (envelope, _, _) = Envelope::<CS>::seal_raw(
randomized_pwd_hasher,
&randomized_pwd_hasher,
nonce.into(),
[pubkey_bytes.as_slice()].into_iter(),
InnerEnvelopeMode::Internal,
)
.unwrap();
)?;
let envelope_bytes = envelope.serialize();
let mut input = Vec::new();
@@ -409,9 +408,9 @@ fn triple_dh_credential_request_roundtrip() -> Result<(), ProtocolError> {
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize,
// CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let alpha = random_element::<CS>();
let alpha_bytes = OprfGroup::<CS>::serialize_elem(alpha);
@@ -466,17 +465,17 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
let elem = random_element::<CS>();
let elem_bytes = OprfGroup::<CS>::serialize_elem(elem);
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let mut masking_nonce = [0u8; 32];
rng.fill_bytes(&mut masking_nonce);
@@ -504,7 +503,7 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> {
input.extend_from_slice(&masked_response);
input.extend_from_slice(&ke2m);
let l2 = CredentialResponse::<CS>::deserialize(&input).unwrap();
let l2 = CredentialResponse::<CS>::deserialize(&input)?;
let l2_bytes = l2.serialize();
assert_eq!(input, *l2_bytes);
@@ -550,17 +549,17 @@ fn sigma_i_ecdsa_credential_response_roundtrip() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
let pt = random_point::<CS>();
let pt_bytes = KeGroup::<CS>::serialize_pk(&pt);
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let mut masking_nonce = [0u8; 32];
rng.fill_bytes(&mut masking_nonce);
@@ -630,7 +629,7 @@ fn triple_dh_credential_finalization_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
@@ -661,7 +660,7 @@ fn sigma_i_ecdsa_credential_finalization_roundtrip() -> Result<(), ProtocolError
where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
@@ -696,16 +695,16 @@ fn triple_dh_client_login_roundtrip() -> Result<(), ProtocolError> {
// CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength,
{
let pw = b"hunter2";
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut client_nonce = [0; NonceLen::USIZE];
@@ -762,7 +761,7 @@ fn triple_dh_ke1_message_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::USIZE];
@@ -798,7 +797,7 @@ fn triple_dh_ke2_message_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default();
@@ -839,7 +838,7 @@ fn sigma_i_ecdsa_ke2_message_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default();
@@ -878,7 +877,7 @@ fn triple_dh_ke3_message_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
@@ -910,7 +909,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let mut mac = Output::<OprfHash<CS>>::default();
@@ -934,7 +933,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
proptest! {
#[test]
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..core::mem::size_of::<usize>())) {
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..size_of::<usize>())) {
use generic_array::typenum::{U0, U1, U2, U3, U4, U5, U6, U7};
let input = os2ip(&bytes).unwrap();
+78 -86
View File
@@ -19,8 +19,9 @@ use generic_array::{ArrayLength, GenericArray};
#[cfg(feature = "kem")]
use ml_kem::MlKem768;
use rand::SeedableRng;
use rand::rngs::OsRng;
use rand::rngs::SysRng;
use rand_chacha::ChaCha20Rng;
use rand_core::UnwrapErr;
use serde_json::Value;
use subtle::ConstantTimeEq;
use voprf::Group as _;
@@ -42,6 +43,7 @@ use crate::messages::{
RegistrationResponseLen, RegistrationUploadLen,
};
use crate::opaque::*;
use crate::tests::decode;
use crate::tests::mock_rng::CycleRng;
use crate::*;
@@ -70,7 +72,7 @@ macro_rules! ciphersuite_types {
macro_rules! generate {
($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($output:ident)) => {
paste::paste! {
pastey::paste! {
$(#[$attr])*
{
let parameters = generate_parameters::<$name>()?;
@@ -89,7 +91,7 @@ macro_rules! generate {
macro_rules! run_all {
($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($fn:ident $(, $par:expr)*)) => {
paste::paste! {
pastey::paste! {
$(#[$attr])*
$fn::<$name>(super::full_test_vectors::[<TEST_VECTOR_ $name:snake:upper>] $(, $par)*)?;
}
@@ -118,7 +120,7 @@ macro_rules! oprf_ciphersuites {
#[$ke_attr_1:meta] #[$ke_attr_2:meta] [$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => {
paste::paste! {
pastey::paste! {
$($macro!(#[$ke_attr_1] #[$ke_attr_2] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
}
};
@@ -127,7 +129,7 @@ macro_rules! oprf_ciphersuites {
#[$ke_attr:meta] [$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => {
paste::paste! {
pastey::paste! {
$($macro!(#[$ke_attr] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
}
};
@@ -136,7 +138,7 @@ macro_rules! oprf_ciphersuites {
[$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => {
paste::paste! {
pastey::paste! {
$($macro!($(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
}
}
@@ -196,7 +198,7 @@ macro_rules! sigma_i_ciphersuites {
$macro:ident!$par:tt =>
[$($(#[$sig_attr:meta])? [$sig_name:ident, $sig:ty]),+$(,)?],
) => {
paste::paste! {
pastey::paste! {
$(
oprf_ciphersuites!(
$macro!$par => [
@@ -261,10 +263,6 @@ pub struct TestVectorParameters {
static STR_PASSWORD: &str = "password";
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
fn populate_test_vectors(values: &Value) -> TestVectorParameters {
TestVectorParameters {
client_s_pk: decode(values, "client_s_pk").unwrap(),
@@ -521,37 +519,37 @@ where
<CS::KeyExchange as KeyExchange>::KE3Message: Serialize,
// ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
ClientRegistrationLen<CS>: ArrayLength,
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
RegistrationResponseLen<CS>: ArrayLength,
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
// CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
use rand::RngCore;
use rand::Rng;
use crate::keypair::KeyPair;
@@ -588,20 +586,19 @@ where
let dummy_client_pk = dummy_client_pk.serialize();
let server_setup = ServerSetup::<CS>::deserialize(
&[
oprf_seed.as_ref(),
&server_s_kp.private().serialize(),
&dummy_client_pk,
oprf_seed.as_slice(),
server_s_kp.private().serialize().as_slice(),
dummy_client_pk.as_slice(),
]
.concat(),
)
.unwrap();
)?;
let blinding_factor = <OprfGroup<CS> as voprf::Group>::random_scalar(&mut rng);
let blinding_factor = <OprfGroup<CS> as voprf::Group>::random_scalar(&mut rng)?;
let blinding_factor_bytes = OprfGroup::<CS>::serialize_scalar(blinding_factor);
let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec());
let client_registration_start_result =
ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password).unwrap();
ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password)?;
let blinding_factor_bytes_returned = OprfGroup::<CS>::serialize_scalar(
client_registration_start_result
.state
@@ -620,8 +617,8 @@ where
&server_setup,
client_registration_start_result.message,
credential_identifier,
)
.unwrap();
)?;
let registration_response_bytes = server_registration_start_result.message.serialize();
let mut client_s_sk_and_nonce: Vec<u8> = Vec::new();
@@ -629,21 +626,18 @@ where
client_s_sk_and_nonce.extend_from_slice(&envelope_nonce);
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let client_registration_finish_result = client_registration_start_result
.state
.finish(
&mut finish_registration_rng,
password,
server_registration_start_result.message,
ClientRegistrationFinishParameters::new(
Identifiers {
client: Some(id_u),
server: Some(id_s),
},
None,
),
)
.unwrap();
let client_registration_finish_result = client_registration_start_result.state.finish(
&mut finish_registration_rng,
password,
server_registration_start_result.message,
ClientRegistrationFinishParameters::new(
Identifiers {
client: Some(id_u),
server: Some(id_s),
},
None,
),
)?;
let registration_upload_bytes = client_registration_finish_result.message.serialize();
let password_file = ServerRegistration::finish(client_registration_finish_result.message);
@@ -656,7 +650,7 @@ where
let mut client_login_start_rng = CycleRng::new(client_login_start);
let client_login_start_result =
ClientLogin::<CS>::start(&mut client_login_start_rng, password).unwrap();
ClientLogin::<CS>::start(&mut client_login_start_rng, password)?;
let credential_request_bytes = client_login_start_result.message.serialize();
let client_login_state = client_login_start_result.state.serialize().to_vec();
@@ -683,27 +677,23 @@ where
server: Some(id_s),
},
},
)
.unwrap();
)?;
let credential_response_bytes = server_login_start_result.message.serialize();
let server_login_state = server_login_start_result.state.serialize();
let client_login_finish_result = client_login_start_result
.state
.finish(
&mut CycleRng::new(client_sig_rng.to_vec()),
password,
server_login_start_result.message,
ClientLoginFinishParameters::new(
Some(context),
Identifiers {
client: Some(id_u),
server: Some(id_s),
},
None,
),
)
.unwrap();
let client_login_finish_result = client_login_start_result.state.finish(
&mut CycleRng::new(client_sig_rng.to_vec()),
password,
server_login_start_result.message,
ClientLoginFinishParameters::new(
Some(context),
Identifiers {
client: Some(id_u),
server: Some(id_s),
},
None,
),
)?;
let credential_finalization_bytes = client_login_finish_result.message.serialize();
Ok(TestVectorParameters {
@@ -787,7 +777,7 @@ fn test_registration_request() -> Result<(), ProtocolError> {
where
// ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
ClientRegistrationLen<CS>: ArrayLength,
{
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
let mut rng = CycleRng::new(parameters.blinding_factor.to_vec());
@@ -822,14 +812,16 @@ fn test_serialization() -> Result<(), ProtocolError> {
ClientRegistration::<CS>::start(&mut rng, &parameters.password)?;
// Test the bincode serialization (binary).
let cfg = bincode_next::config::standard();
let registration_request =
bincode::serialize(&client_registration_start_result.message).unwrap();
bincode_next::serde::encode_to_vec(&client_registration_start_result.message, cfg)
.unwrap();
assert_eq!(
registration_request.len(),
RegistrationRequestLen::<CS>::USIZE
);
let registration_request: RegistrationRequest<CS> =
bincode::deserialize(&registration_request).unwrap();
let (registration_request, _): (RegistrationRequest<CS>, usize) =
bincode_next::serde::decode_from_slice(&registration_request, cfg).unwrap();
assert_eq!(
hex::encode(client_registration_start_result.message.serialize()),
hex::encode(registration_request.serialize()),
@@ -852,7 +844,7 @@ fn test_registration_response() -> Result<(), ProtocolError> {
where
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
RegistrationResponseLen<CS>: ArrayLength,
{
let parameters = populate_test_vectors(
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
@@ -894,8 +886,8 @@ fn test_registration_upload() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
{
let parameters = populate_test_vectors(
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
@@ -945,8 +937,8 @@ fn test_password_file() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
{
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -977,13 +969,13 @@ fn test_credential_request() -> Result<(), ProtocolError> {
// CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength,
{
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -1024,12 +1016,12 @@ fn test_credential_response() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -1182,8 +1174,8 @@ fn test_complete_flow<CS: CipherSuite>(
login_password: &[u8],
) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier";
let mut client_rng = OsRng;
let mut server_rng = OsRng;
let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, registration_password)?;
@@ -1330,8 +1322,8 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier";
let password = b"password";
let mut client_rng = OsRng;
let mut server_rng = OsRng;
let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, password)?;
@@ -1377,8 +1369,8 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier";
let password = b"password";
let mut client_rng = OsRng;
let mut server_rng = OsRng;
let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, password)?;
+24 -17
View File
@@ -9,9 +9,10 @@
use core::cmp::min;
use std::vec::Vec;
use rand::{CryptoRng, Error, RngCore};
use core::convert::Infallible;
use rand_core::{TryCryptoRng, TryRng};
/// A simple implementation of `RngCore` for testing purposes.
/// A simple implementation of `Rng` for testing purposes.
///
/// This generates a cyclic sequence (i.e. cycles over an initial buffer)
#[derive(Clone, Debug)]
@@ -38,29 +39,35 @@ fn rotate_left<T>(data: &mut [T], steps: usize) {
data.reverse();
}
impl RngCore for CycleRng {
fn next_u32(&mut self) -> u32 {
unimplemented!()
impl TryRng for CycleRng {
type Error = Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
let mut buf = [0u8; 4];
self.try_fill_bytes(&mut buf)?;
Ok(u32::from_le_bytes(buf))
}
#[inline]
fn next_u64(&mut self) -> u64 {
unimplemented!()
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
let mut buf = [0u8; 8];
self.try_fill_bytes(&mut buf)?;
Ok(u64::from_le_bytes(buf))
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
let len = min(self.v.len(), dest.len());
dest[..len].copy_from_slice(&self.v[..len]);
rotate_left(&mut self.v, len);
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
dest[..len].copy_from_slice(&self.v[..len]);
rotate_left(&mut self.v, len);
Ok(())
}
}
// This is meant for testing only
impl CryptoRng for CycleRng {}
impl TryCryptoRng for CycleRng {}
+7
View File
@@ -6,6 +6,9 @@
// of this source tree. You may select, at your option, one of the above-listed
// licenses.
use serde_json::Value;
use std::vec::Vec;
mod full_test;
#[rustfmt::skip]
#[allow(dead_code)]
@@ -14,3 +17,7 @@ pub mod mock_rng;
mod parser;
mod rfc9807_vectors;
mod test_opaque_vectors;
pub(crate) fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
+4 -8
View File
@@ -15,20 +15,18 @@ pub(crate) fn rfc_to_json(input: &str) -> String {
}
fn parse_vector_types(input: &str) -> String {
let re = regex::Regex::new(r" (?P<type>.+?) Test Vectors").unwrap();
let re = regex::Regex::new(r" {2}(?P<type>.+?) Test Vectors").unwrap();
let mut vector_types = vec![];
let chunks: Vec<&str> = re.split(input).collect();
let mut count = 1;
for caps in re.captures_iter(input) {
for (count, caps) in (1..).zip(re.captures_iter(input)) {
let vector_type = format!(
"\"{}\": [\n {} \n]",
&caps["type"].trim(),
parse_ciphersuites(chunks[count])
);
vector_types.push(vector_type);
count += 1;
}
vector_types.join(",\n")
@@ -36,15 +34,14 @@ fn parse_vector_types(input: &str) -> String {
fn parse_ciphersuites(input: &str) -> String {
let re = regex::Regex::new(
r" Configuration\n(.|\n)*?OPRF: (?P<oprf>.*?)\n(.|\n)*?Group: (?P<group>.*?)\n",
r" Configuration\n([\s\S])*?OPRF: (?P<oprf>.*?)\n([\s\S])*?Group: (?P<group>.*?)\n",
)
.unwrap();
let mut ciphersuites = vec![];
let chunks: Vec<&str> = re.split(input).collect();
let mut count = 1;
for caps in re.captures_iter(input) {
for (count, caps) in (1..).zip(re.captures_iter(input)) {
let ciphersuite = format!(
"{{ \"{}, {}\": {{ {} }} }}",
&caps["oprf"],
@@ -52,7 +49,6 @@ fn parse_ciphersuites(input: &str) -> String {
parse_params(chunks[count])
);
ciphersuites.push(ciphersuite);
count += 1;
}
ciphersuites.join(",\n")
+34 -35
View File
@@ -10,13 +10,6 @@ use core::ops::Add;
use std::vec;
use std::vec::Vec;
use digest::OutputSizeUser;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use rand::RngCore;
use rand::rngs::OsRng;
use serde_json::Value;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
use crate::envelope::EnvelopeLen;
use crate::errors::*;
@@ -30,8 +23,16 @@ use crate::messages::{
RegistrationResponseLen, RegistrationUploadLen,
};
use crate::opaque::*;
use crate::tests::decode;
use crate::tests::mock_rng::CycleRng;
use crate::*;
use digest::OutputSizeUser;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use rand::Rng;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use serde_json::Value;
#[allow(non_snake_case)]
#[derive(Debug)]
@@ -87,19 +88,15 @@ macro_rules! parse_default {
};
}
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> OpaqueTestVectorParameters {
let mut rng = OsRng;
let mut rng = UnwrapErr(SysRng);
OpaqueTestVectorParameters {
dummy_public_key: {
match decode(values, "client_public_key") {
Some(value) => value,
None => KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut OsRng)).to_vec(),
}
decode(values, "client_public_key").unwrap_or_else(|| {
KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut UnwrapErr(SysRng)))
.to_vec()
})
},
dummy_masking_key: {
match decode(values, "masking_key") {
@@ -151,8 +148,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
{
let password_file = ServerRegistration::<CS>::finish(
@@ -185,12 +182,14 @@ fn tests() -> Result<(), ProtocolError> {
serde_json::from_str(super::parser::rfc_to_json(super::rfc9807_vectors::VECTORS).as_str())
.expect("Could not parse json");
std::eprintln!("{}", serde_json::to_string_pretty(&rfc).unwrap());
#[cfg(feature = "ristretto255")]
{
struct Ristretto255Sha512NoKsf;
impl CipherSuite for Ristretto255Sha512NoKsf {
type OprfCs = crate::Ristretto255;
type KeyExchange = TripleDh<crate::Ristretto255, sha2::Sha512>;
type OprfCs = Ristretto255;
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
type Ksf = Identity;
}
@@ -331,7 +330,7 @@ fn test_registration_response<CS: CipherSuite>(
where
// RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
RegistrationResponseLen<CS>: ArrayLength,
{
for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize(
@@ -370,8 +369,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
{
for parameters in tvs {
let mut rng = CycleRng::new(parameters.blind_registration.to_vec());
@@ -417,7 +416,7 @@ where
// CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
CredentialRequestLen<CS>: ArrayLength,
{
for parameters in tvs {
let client_login_start = [
@@ -444,18 +443,18 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize(
@@ -530,7 +529,7 @@ where
ClientLogin::<CS>::start(&mut client_login_start_rng, &parameters.password)?;
let client_login_finish_result = client_login_start_result.state.finish(
&mut OsRng,
&mut UnwrapErr(SysRng),
&parameters.password,
CredentialResponse::<CS>::deserialize(&parameters.KE2)?,
ClientLoginFinishParameters::new(
@@ -576,8 +575,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload
{
for parameters in tvs {
@@ -644,12 +643,12 @@ where
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
CredentialResponseLen<CS>: ArrayLength,
{
for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize(