diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d4e28ce3..70f0a78d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,13 +13,20 @@ jobs: fail-fast: false matrix: backend_feature: - - ristretto255_u64 - - ristretto255_u32 - - p256 - - x25519_u64,ristretto255_u64 + - --features ristretto255_u64,ristretto255_voprf + - --features ristretto255_u32,ristretto255_voprf + - + - --features x25519_u64,ristretto255_u64,ristretto255_voprf + - --features x25519_u32,ristretto255_u32,ristretto255_voprf + - --features x25519_u64 + - --features x25519_u32 + frontend_feature: + - + - --features slow-hash + - --features serde toolchain: - stable - - 1.56.1 + - 1.57.0 name: test steps: - name: Checkout sources @@ -36,13 +43,13 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --no-default-features --features ${{ matrix.backend_feature }} + args: --no-default-features ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }} - name: Run cargo test with std uses: actions-rs/cargo@v1 with: command: test - args: --no-default-features --features std --features ${{ matrix.backend_feature }} + args: --no-default-features --features std ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }} cross-test: name: Test on ${{ matrix.target }} (using cross) @@ -54,43 +61,21 @@ jobs: # 32-bit x86 - i686-unknown-linux-gnu backend_feature: - - ristretto255_u64 - - ristretto255_u32 - - p256 - - x25519_u64,ristretto255_u64 + - --features ristretto255_u64,ristretto255_voprf + - --features ristretto255_u32,ristretto255_voprf + - + - x25519_u64,ristretto255_u64,ristretto255_voprf + - x25519_u32,ristretto255_u64,ristretto255_voprf + - x25519_u64 + - x25519_u32 steps: - uses: actions/checkout@v2 - uses: hecrj/setup-rust-action@v1 - run: cargo install cross # Note: just use `cross` as you would `cargo`, but always # pass the `--target=${{ matrix.target }}` arg. (Yes, really). - - run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.backend_feature }} - - run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features std --features ${{ matrix.backend_feature }} - - feature-test: - name: Test on ${{ matrix.target }} with ${{ matrix.frontend_feature }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - backend_feature: - - ristretto255_u64 - - ristretto255_u32 - - p256 - - ristretto255_u64,p256 - - x25519_u64,ristretto255_u64 - - x25519_u32,ristretto255_u32 - - x25519_u64,p256 - - x25519_u32,p256 - - x25519_u64,ristretto255_u64,p256 - frontend_feature: - - slow-hash - - serde - steps: - - uses: actions/checkout@v2 - - uses: hecrj/setup-rust-action@v1 - - run: cargo test --verbose --features ${{ matrix.frontend_feature }} --no-default-features --features ${{ matrix.backend_feature }} - - run: cargo test --verbose --features ${{ matrix.frontend_feature }},std --no-default-features --features ${{ matrix.backend_feature }} + - run: cross test --verbose --target=${{ matrix.target }} --no-default-features ${{ matrix.backend_feature }} + - run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features std ${{ matrix.backend_feature }} simple-login-test: runs-on: ubuntu-latest @@ -99,7 +84,7 @@ jobs: matrix: toolchain: - stable - - 1.56.1 + - 1.57.0 name: test simple_login command-line example steps: - name: install expect @@ -122,7 +107,7 @@ jobs: matrix: toolchain: - stable - - 1.56.1 + - 1.57.0 name: test digital_locker command-line example steps: - name: install expect @@ -150,10 +135,13 @@ jobs: # for any no_std target - thumbv6m-none-eabi backend_feature: - - ristretto255_u64 - - ristretto255_u32 - - p256 - - x25519_u64,ristretto255_u64 + - ristretto255_u64,ristretto255_voprf + - ristretto255_u32,ristretto255_voprf + - + - x25519_u64,ristretto255_u64,ristretto255_voprf + - x25519_u32,ristretto255_u32,ristretto255_voprf + - x25519_u64 + - x25519_u32 frontend_feature: - slow-hash - serde @@ -170,10 +158,13 @@ jobs: fail-fast: false matrix: backend_feature: - - ristretto255_u64 - - ristretto255_u32 - - p256 - - x25519_u64,ristretto255_u64 + - --features ristretto255_u64,ristretto255_voprf + - --features ristretto255_u32,ristretto255_voprf + - + - --features x25519_u64,ristretto255_u64,ristretto255_voprf + - --features x25519_u32,ristretto255_u32,ristretto255_voprf + - --features x25519_u32 + - --features x25519_u32 steps: - name: Checkout sources uses: actions/checkout@v2 @@ -189,7 +180,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: bench - args: --no-default-features --features ${{ matrix.backend_feature }} --no-run + args: --no-default-features ${{ matrix.backend_feature }} --no-run clippy: name: cargo clippy @@ -210,7 +201,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-targets -- -D warnings + args: --all-targets --features slow-hash,std,x25519_u64 -- -D warnings - name: Run cargo doc uses: actions-rs/cargo@v1 @@ -218,7 +209,7 @@ jobs: RUSTDOCFLAGS: -D warnings with: command: doc - args: --no-deps --document-private-items --features p256,slow-hash,std + args: --no-deps --document-private-items --features slow-hash,std,x25519_u64 format: name: cargo fmt diff --git a/Cargo.toml b/Cargo.toml old mode 100755 new mode 100644 index 672707dc..6899371d --- a/Cargo.toml +++ b/Cargo.toml @@ -8,47 +8,27 @@ license = "Apache-2.0 OR MIT" name = "opaque-ke" readme = "README.md" repository = "https://github.com/novifinancial/opaque-ke" -rust-version = "1.56" +rust-version = "1.57" version = "2.0.0-pre.1" [features] -default = ["ristretto255_u64", "serde"] -p256 = ["p256_", "voprf/p256"] -ristretto255 = [] -ristretto255_fiat_u32 = [ - "curve25519-dalek/fiat_u32_backend", - "ristretto255", - "voprf/ristretto255_fiat_u32", -] -ristretto255_fiat_u64 = [ - "curve25519-dalek/fiat_u64_backend", - "ristretto255", - "voprf/ristretto255_fiat_u64", -] -ristretto255_simd = [ - "curve25519-dalek/simd_backend", - "ristretto255", - "voprf/ristretto255_simd", -] -ristretto255_u32 = [ - "curve25519-dalek/u32_backend", - "ristretto255", - "voprf/ristretto255_u32", -] -ristretto255_u64 = [ - "curve25519-dalek/u64_backend", - "ristretto255", - "voprf/ristretto255_u64", -] +default = ["ristretto255_u64", "ristretto255_voprf", "serde"] +ristretto255 = ["curve25519-dalek", "voprf/ristretto255"] +ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"] +ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"] +ristretto255_simd = ["curve25519-dalek/simd_backend", "ristretto255"] +ristretto255_u32 = ["curve25519-dalek/u32_backend", "ristretto255"] +ristretto255_u64 = ["curve25519-dalek/u64_backend", "ristretto255"] +ristretto255_voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"] serde = ["serde_", "generic-array/serde", "voprf/serde"] slow-hash = ["argon2"] std = ["getrandom", "rand/std", "rand/std_rng", "voprf/std"] -x25519 = [] +x25519 = ["curve25519-dalek-3"] x25519_fiat_u32 = ["x25519", "x25519-dalek/fiat_u32_backend"] x25519_fiat_u64 = ["x25519", "x25519-dalek/fiat_u64_backend"] # x25519-dalek isn't properly re-exposing `simd_backend`. x25519_simd = [ - "curve25519-dalek/simd_backend", + "curve25519-dalek-3/simd_backend", "x25519", "x25519-dalek/nightly", ] @@ -60,26 +40,23 @@ argon2 = { version = "0.3", default-features = false, features = [ "alloc", ], optional = true } constant_time_eq = "0.1" -curve25519-dalek = { version = "3", default-features = false, optional = true } -derive-where = { version = "1.0.0-rc.1", features = ["zeroize"] } +curve25519-dalek = { version = "=4.0.0-pre.1", default-features = false, optional = true } +curve25519-dalek-3 = { version = "3", package = "curve25519-dalek", default-features = false, optional = true } +derive-where = { version = "=1.0.0-rc.3", features = ["zeroize-on-drop"] } digest = "0.10" displaydoc = { version = "0.2", default-features = false } +elliptic-curve = { version = "0.12.0-pre.1", features = ["hash2curve", "sec1"] } generic-array = "0.14" getrandom = { version = "0.2", optional = true } hkdf = "0.12" hmac = "0.12" -p256_ = { package = "p256", version = "0.10", default-features = false, features = [ - "arithmetic", -], optional = true } rand = { version = "0.8", default-features = false } serde_ = { version = "1", package = "serde", default-features = false, features = [ "derive", ], optional = true } subtle = { version = "2.3", default-features = false } -voprf = { git = "https://github.com/novifinancial/voprf", rev = "55ef981a3f9a12eddd8c372ffdf51818011343ee", default-features = false, features = [ - "danger", -] } -x25519-dalek = { version = "1", default-features = false, optional = true } +voprf = { version = "0.3", default-features = false, features = ["danger"] } +x25519-dalek = { version = "=2.0.0-pre.1", default-features = false, optional = true } zeroize = { version = "1", features = ["zeroize_derive"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -93,7 +70,12 @@ criterion = "0.3" hex = "0.4" json = "0.12" lazy_static = "1" +p256 = { version = "=0.11.0-pre.0", default-features = false, features = [ + "hash2curve", + "voprf", +] } proptest = "1" +rand = "0.8" regex = "1" rustyline = "9" serde_json = "1" @@ -102,3 +84,14 @@ sha2 = "0.10" [[bench]] harness = false name = "opaque" + +[package.metadata.docs.rs] +features = ["std", "slow-hash", "x25519_u64"] +targets = [] + +[patch.crates-io] +chacha20 = { git = "https://github.com/RustCrypto/stream-ciphers" } +chacha20poly1305 = { git = "https://github.com/khonsulabs/aeads", branch = "update-dependencies" } +derive-where = { git = "https://github.com/ModProg/derive-where" } +poly1305 = { git = "https://github.com/RustCrypto/universal-hashes" } +voprf = { git = "https://github.com/khonsulabs/voprf", branch = "v08" } diff --git a/README.md b/README.md index 6793ee61..9465a5d3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ opaque-ke = "0.6.0" ### Minimum Supported Rust Version -Rust **1.56** or higher. +Rust **1.57** or higher. Audit ----- diff --git a/benches/opaque.rs b/benches/opaque.rs index 200a5717..d5ed20eb 100644 --- a/benches/opaque.rs +++ b/benches/opaque.rs @@ -20,26 +20,24 @@ static SUFFIX: &str = "ristretto255_u32"; static SUFFIX: &str = "ristretto255_fiat_u64"; #[cfg(feature = "ristretto255_fiat_u32")] static SUFFIX: &str = "ristretto255_fiat_u32"; -#[cfg(all(not(feature = "ristretto255"), feature = "p256"))] +#[cfg(all(not(feature = "ristretto255")))] static SUFFIX: &str = "p256"; struct Default; #[cfg(feature = "ristretto255")] impl CipherSuite for Default { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = opaque_ke::Ristretto255; + type KeGroup = opaque_ke::Ristretto255; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha512; type SlowHash = opaque_ke::slow_hash::NoOpHash; } #[cfg(not(feature = "ristretto255"))] impl CipherSuite for Default { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; + type OprfGroup = p256::NistP256; + type KeGroup = p256::NistP256; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha256; type SlowHash = opaque_ke::slow_hash::NoOpHash; } diff --git a/examples/digital_locker.rs b/examples/digital_locker.rs index c04effc0..c7b8ba1d 100644 --- a/examples/digital_locker.rs +++ b/examples/digital_locker.rs @@ -49,19 +49,17 @@ struct Default; #[cfg(feature = "ristretto255")] impl CipherSuite for Default { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = opaque_ke::Ristretto255; + type KeGroup = opaque_ke::Ristretto255; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha512; type SlowHash = opaque_ke::slow_hash::NoOpHash; } #[cfg(not(feature = "ristretto255"))] impl CipherSuite for Default { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; + type OprfGroup = p256::NistP256; + type KeGroup = p256::NistP256; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha256; type SlowHash = opaque_ke::slow_hash::NoOpHash; } diff --git a/examples/simple_login.rs b/examples/simple_login.rs index 4cb50220..77c060ba 100644 --- a/examples/simple_login.rs +++ b/examples/simple_login.rs @@ -43,19 +43,17 @@ struct Default; #[cfg(feature = "ristretto255")] impl CipherSuite for Default { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = opaque_ke::Ristretto255; + type KeGroup = opaque_ke::Ristretto255; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha512; type SlowHash = opaque_ke::slow_hash::NoOpHash; } #[cfg(not(feature = "ristretto255"))] impl CipherSuite for Default { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; + type OprfGroup = p256::NistP256; + type KeGroup = p256::NistP256; type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; - type Hash = sha2::Sha256; type SlowHash = opaque_ke::slow_hash::NoOpHash; } diff --git a/scripts/simple_login.exp b/scripts/simple_login.exp old mode 100755 new mode 100644 diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs index 2bbe8687..16e0a4ac 100644 --- a/src/ciphersuite.rs +++ b/src/ciphersuite.rs @@ -9,8 +9,8 @@ //! OPAQUE use digest::core_api::{BlockSizeUser, CoreProxy}; -use generic_array::typenum::{IsLess, Le, NonZero, U256}; -use voprf::Group as OprfGroup; +use digest::OutputSizeUser; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, U256}; use crate::hash::{Hash, ProxyHash}; use crate::key_exchange::group::KeGroup; @@ -28,21 +28,24 @@ use crate::slow_hash::SlowHash; /// * `SlowHash`: A slow hashing function, typically used for password hashing pub trait CipherSuite where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// A finite cyclic group along with a point representation along with an /// extension trait PasswordToCurve that allows some customization on how to /// hash a password to a curve point. See `group::Group`. - type OprfGroup: OprfGroup; + type OprfGroup: voprf::CipherSuite; /// A `Group` used for the `KeyExchange`. type KeGroup: KeGroup; /// A key exchange protocol - type KeyExchange: KeyExchange; - /// The main hash function use (for HKDF computations and hashing - /// transcripts) - type Hash: Hash; + type KeyExchange: KeyExchange, Self::KeGroup>; /// A slow hashing function, typically used for password hashing - type SlowHash: SlowHash; + type SlowHash: SlowHash; } + +pub(crate) type OprfGroup = <::OprfGroup as voprf::CipherSuite>::Group; +pub(crate) type OprfHash = <::OprfGroup as voprf::CipherSuite>::Hash; diff --git a/src/envelope.rs b/src/envelope.rs old mode 100755 new mode 100644 index 31e7c7e9..468e924a --- a/src/envelope.rs +++ b/src/envelope.rs @@ -8,19 +8,18 @@ use core::convert::TryFrom; use core::ops::Add; -use derive_where::DeriveWhere; +use derive_where::derive_where; use digest::core_api::{BlockSizeUser, CoreProxy}; -use digest::Output; +use digest::{Output, OutputSizeUser}; use generic_array::sequence::Concat; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U2, U256, U32}; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U2, U256, U32}; use generic_array::{ArrayLength, GenericArray}; use hkdf::Hkdf; use hmac::{Hmac, Mac}; use rand::{CryptoRng, RngCore}; -use voprf::Group; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfHash}; use crate::errors::utils::check_slice_size; use crate::errors::{InternalError, ProtocolError}; use crate::hash::{Hash, OutputSize, ProxyHash}; @@ -36,13 +35,18 @@ const STR_PRIVATE_KEY: [u8; 10] = *b"PrivateKey"; const STR_OPAQUE_DERIVE_AUTH_KEY_PAIR: [u8; 24] = *b"OPAQUE-DeriveAuthKeyPair"; type NonceLen = U32; -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)] -#[zeroize(drop)] +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)] pub(crate) enum InnerEnvelopeMode { Zero = 0, Internal = 1, } +impl Zeroize for InnerEnvelopeMode { + fn zeroize(&mut self) { + *self = Self::Zero + } +} + impl TryFrom for InnerEnvelopeMode { type Error = ProtocolError; fn try_from(x: u8) -> Result { @@ -61,17 +65,46 @@ impl TryFrom for InnerEnvelopeMode { /// The specification update has simplified this assumption by taking an /// XOR-based approach without compromising on security, and to avoid the /// confusion around the implementation of an RKR-secure encryption. -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] +#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub(crate) struct Envelope where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - mode: InnerEnvelopeMode, + pub(crate) mode: InnerEnvelopeMode, nonce: GenericArray, - hmac: Output, + hmac: Output>, +} + +impl Drop for Envelope +where + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + fn drop(&mut self) { + self.mode.zeroize(); + self.nonce.zeroize(); + self.hmac.zeroize(); + } +} + +impl ZeroizeOnDrop for Envelope +where + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ } // Note that this struct represents an envelope that has been "opened" with the @@ -80,12 +113,15 @@ where // contents. pub(crate) struct OpenedEnvelope<'a, CS: CipherSuite> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { pub(crate) client_static_keypair: KeyPair, - pub(crate) export_key: Output, + pub(crate) export_key: Output>, pub(crate) id_u: Serialize<'a, U2, ::PkLen>, pub(crate) id_s: Serialize<'a, U2, ::PkLen>, } @@ -100,31 +136,34 @@ where } #[cfg(not(test))] -type SealRawResult = (Envelope, Output); +type SealRawResult = (Envelope, Output>); #[cfg(test)] -type SealRawResult = (Envelope, Output, Output); +type SealRawResult = (Envelope, Output>, Output>); #[cfg(not(test))] -type SealResult = (Envelope, PublicKey, Output); +type SealResult = (Envelope, PublicKey, Output>); #[cfg(test)] type SealResult = ( Envelope, PublicKey, - Output, - Output, + Output>, + Output>, ); -pub(crate) type EnvelopeLen = Sum>; +pub(crate) type EnvelopeLen = Sum>>; impl Envelope where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { #[allow(clippy::type_complexity)] pub(crate) fn seal( rng: &mut R, - randomized_pwd_hasher: Hkdf, + randomized_pwd_hasher: Hkdf>, server_s_pk: &PublicKey, ids: Identifiers, ) -> Result, ProtocolError> { @@ -136,12 +175,13 @@ where build_inner_envelope_internal::(randomized_pwd_hasher.clone(), nonce)?, ); + let server_s_pk_bytes = server_s_pk.to_bytes(); let (id_u, id_s) = bytestrings_from_identifiers::( ids, - client_s_pk.to_arr(), - server_s_pk.to_arr(), + client_s_pk.to_bytes(), + server_s_pk_bytes.clone(), )?; - let aad = construct_aad(id_u.iter(), id_s.iter(), server_s_pk); + let aad = construct_aad(id_u.iter(), id_s.iter(), &server_s_pk_bytes); let result = Self::seal_raw(randomized_pwd_hasher, nonce, aad, mode)?; Ok(( @@ -157,13 +197,13 @@ where /// 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, + randomized_pwd_hasher: Hkdf>, nonce: GenericArray, aad: impl Iterator, mode: InnerEnvelopeMode, ) -> Result, InternalError> { - let mut hmac_key = Output::::default(); - let mut export_key = Output::::default(); + let mut hmac_key = Output::>::default(); + let mut export_key = Output::>::default(); randomized_pwd_hasher .expand_multi_info(&[&nonce, &STR_AUTH_KEY], &mut hmac_key) @@ -172,8 +212,8 @@ where .expand_multi_info(&[&nonce, &STR_EXPORT_KEY], &mut export_key) .map_err(|_| InternalError::HkdfError)?; - let mut hmac = - Hmac::::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?; + let mut hmac = Hmac::>::new_from_slice(&hmac_key) + .map_err(|_| InternalError::HmacError)?; hmac.update(&nonce); hmac.update_iter(aad); @@ -193,7 +233,7 @@ where pub(crate) fn open<'a>( &self, - randomized_pwd_hasher: Hkdf, + randomized_pwd_hasher: Hkdf>, server_s_pk: PublicKey, optional_ids: Identifiers<'a>, ) -> Result, ProtocolError> { @@ -206,12 +246,13 @@ where } }; + let server_s_pk_bytes = server_s_pk.to_bytes(); let (id_u, id_s) = bytestrings_from_identifiers::( optional_ids, - client_static_keypair.public().to_arr(), - server_s_pk.to_arr(), + client_static_keypair.public().to_bytes(), + server_s_pk_bytes.clone(), )?; - let aad = construct_aad(id_u.iter(), id_s.iter(), &server_s_pk); + let aad = construct_aad(id_u.iter(), id_s.iter(), &server_s_pk_bytes); let opened = self.open_raw(randomized_pwd_hasher, aad)?; @@ -227,11 +268,11 @@ where /// if the key and aad used to construct the envelope are the same. pub(crate) fn open_raw<'a>( &self, - randomized_pwd_hasher: Hkdf, + randomized_pwd_hasher: Hkdf>, aad: impl Iterator, - ) -> Result, InternalError> { - let mut hmac_key = Output::::default(); - let mut export_key = Output::::default(); + ) -> Result>, InternalError> { + let mut hmac_key = Output::>::default(); + let mut export_key = Output::>::default(); randomized_pwd_hasher .expand(&self.nonce.concat(STR_AUTH_KEY.into()), &mut hmac_key) @@ -240,8 +281,8 @@ where .expand(&self.nonce.concat(STR_EXPORT_KEY.into()), &mut export_key) .map_err(|_| InternalError::HkdfError)?; - let mut hmac = - Hmac::::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?; + let mut hmac = Hmac::>::new_from_slice(&hmac_key) + .map_err(|_| InternalError::HmacError)?; hmac.update(&self.nonce); hmac.update_iter(aad); hmac.verify(&self.hmac) @@ -260,17 +301,17 @@ where } fn hmac_key_size() -> usize { - OutputSize::::USIZE + OutputSize::>::USIZE } pub(crate) fn len() -> usize { - OutputSize::::USIZE + NonceLen::USIZE + OutputSize::>::USIZE + NonceLen::USIZE } pub(crate) fn serialize(&self) -> GenericArray> where // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, { self.nonce.concat(self.hmac.clone()) @@ -305,22 +346,25 @@ where // Helper functions fn build_inner_envelope_internal( - randomized_pwd_hasher: Hkdf, + randomized_pwd_hasher: Hkdf>, nonce: GenericArray, ) -> Result, ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut keypair_seed = GenericArray::<_, ::SkLen>::default(); randomized_pwd_hasher .expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed) .map_err(|_| InternalError::HkdfError)?; let client_static_keypair = KeyPair::::from_private_key_slice( - &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::( - [keypair_seed.as_slice()], - GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), + &CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::>( + &[keypair_seed.as_slice()], + &GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), )?), )?; @@ -328,22 +372,25 @@ where } fn recover_keys_internal( - randomized_pwd_hasher: Hkdf, + randomized_pwd_hasher: Hkdf>, nonce: GenericArray, ) -> Result, ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut keypair_seed = GenericArray::<_, ::SkLen>::default(); randomized_pwd_hasher .expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed) .map_err(|_| InternalError::HkdfError)?; let client_static_keypair = KeyPair::::from_private_key_slice( - &CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::( - [keypair_seed.as_slice()], - GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), + &CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::>( + &[keypair_seed.as_slice()], + &GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), )?), )?; diff --git a/src/errors.rs b/src/errors.rs index e35cd38a..4080a4da 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -31,8 +31,8 @@ pub enum InternalError { }, /// Could not decompress point. PointError, - /// Computing the hash-to-curve function failed - HashToCurveError, + /// Size of input is empty or longer then [`u16::MAX`]. + HashToScalar, /// Computing HKDF failed while deriving subkeys HkdfError, /// Computing HMAC failed while supplying a secret key @@ -45,12 +45,10 @@ pub enum InternalError { /** This error occurs when attempting to open an envelope of the wrong type (base mode, custom identifier) */ IncompatibleEnvelopeModeError, - /// This error occurs when the inner envelope is malformed - InvalidInnerEnvelopeError, /// Error from the OPRF evaluation OprfError(voprf::Error), - /// Error encountered when attempting to produce a keypair - InvalidKeypairError, + /// Error from the OPRF evaluation + OprfInternalError(voprf::InternalError), } impl Debug for InternalError { @@ -69,7 +67,7 @@ impl Debug for InternalError { .field("actual_len", actual_len) .finish(), Self::PointError => f.debug_tuple("PointError").finish(), - Self::HashToCurveError => f.debug_tuple("HashToCurveError").finish(), + Self::HashToScalar => f.debug_tuple("HashToScalar").finish(), Self::HkdfError => f.debug_tuple("HkdfError").finish(), Self::HmacError => f.debug_tuple("HmacError").finish(), Self::SlowHashError => f.debug_tuple("SlowHashError").finish(), @@ -77,9 +75,10 @@ impl Debug for InternalError { Self::IncompatibleEnvelopeModeError => { f.debug_tuple("IncompatibleEnvelopeModeError").finish() } - Self::InvalidInnerEnvelopeError => f.debug_tuple("InvalidInnerEnvelopeError").finish(), Self::OprfError(error) => f.debug_tuple("OprfError").field(error).finish(), - Self::InvalidKeypairError => f.debug_tuple("InvalidKeypairError").finish(), + Self::OprfInternalError(error) => { + f.debug_tuple("OprfInternalError").field(error).finish() + } } } } @@ -103,15 +102,14 @@ impl InternalError { actual_len, }, Self::PointError => InternalError::PointError, - Self::HashToCurveError => InternalError::HashToCurveError, + Self::HashToScalar => InternalError::HashToScalar, Self::HkdfError => InternalError::HkdfError, Self::HmacError => InternalError::HmacError, Self::SlowHashError => InternalError::SlowHashError, Self::SealOpenHmacError => InternalError::SealOpenHmacError, Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError, - Self::InvalidInnerEnvelopeError => InternalError::InvalidInnerEnvelopeError, Self::OprfError(error) => InternalError::OprfError(error), - Self::InvalidKeypairError => InternalError::InvalidKeypairError, + Self::OprfInternalError(error) => InternalError::OprfInternalError(error), } } } @@ -128,6 +126,12 @@ impl From for ProtocolError { } } +impl From for ProtocolError { + fn from(voprf_error: voprf::InternalError) -> Self { + Self::LibraryError(InternalError::OprfInternalError(voprf_error)) + } +} + /// Represents an error in protocol handling #[derive(Clone, Copy, Display, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum ProtocolError { diff --git a/src/impls.rs b/src/impls.rs old mode 100755 new mode 100644 index a579a767..ccdb6376 --- a/src/impls.rs +++ b/src/impls.rs @@ -11,9 +11,12 @@ macro_rules! impl_serialize_and_deserialize_for { #[cfg(feature = "serde")] impl serde_::Serialize for $item where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, $($($path: $bound1 $(+ $bound2)*),+)? { fn serialize(&self, serializer: S) -> Result @@ -27,9 +30,12 @@ macro_rules! impl_serialize_and_deserialize_for { #[cfg(feature = "serde")] impl<'de, CS: CipherSuite> serde_::Deserialize<'de> for $item where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { fn deserialize(deserializer: D) -> Result where @@ -39,15 +45,21 @@ macro_rules! impl_serialize_and_deserialize_for { struct ByteVisitor(core::marker::PhantomData) where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero; + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero; impl<'de, CS: CipherSuite> serde_::de::Visitor<'de> for ByteVisitor where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { type Value = $item; diff --git a/src/key_exchange/group/elliptic_curve.rs b/src/key_exchange/group/elliptic_curve.rs new file mode 100644 index 00000000..fef2f5ff --- /dev/null +++ b/src/key_exchange/group/elliptic_curve.rs @@ -0,0 +1,85 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under both the MIT license found in the +// LICENSE-MIT file in the root directory of this source tree and the Apache +// License, Version 2.0 found in the LICENSE-APACHE file in the root directory +// of this source tree. + +use digest::core_api::BlockSizeUser; +use digest::Digest; +use elliptic_curve::group::cofactor::CofactorGroup; +use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest}; +use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}; +use elliptic_curve::{ + AffinePoint, Curve, FieldSize, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, PublicKey, + Scalar, SecretKey, +}; +use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; +use generic_array::GenericArray; +use rand::{CryptoRng, RngCore}; + +use super::KeGroup; +use crate::errors::InternalError; + +impl KeGroup for G +where + FieldSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + ProjectivePoint: CofactorGroup + ToEncodedPoint, + Scalar: FromOkm, +{ + type Pk = PublicKey; + + type PkLen = as ModulusSize>::CompressedPointSize; + + type Sk = SecretKey; + + type SkLen = FieldSize; + + fn serialize_pk(pk: &Self::Pk) -> GenericArray { + GenericArray::clone_from_slice(pk.to_encoded_point(true).as_bytes()) + } + + fn deserialize_pk(bytes: &GenericArray) -> Result { + PublicKey::from_sec1_bytes(bytes).map_err(|_| InternalError::PointError) + } + + fn random_sk(rng: &mut R) -> Self::Sk { + SecretKey::random(rng) + } + + // Implements the `HashToScalar()` function + fn hash_to_scalar(input: &[&[u8]], dst: &[u8]) -> Result + where + H: Digest + BlockSizeUser, + H::OutputSize: IsLess + IsLessOrEqual, + { + Self::hash_to_scalar::>(input, dst) + .ok() + .and_then(|scalar| Option::>::from(NonZeroScalar::new(scalar))) + .map(SecretKey::from) + .ok_or(InternalError::HashToScalar) + } + + fn public_key(sk: &Self::Sk) -> Self::Pk { + sk.public_key() + } + + fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray { + GenericArray::clone_from_slice( + (pk.to_projective() * sk.to_nonzero_scalar().as_ref()) + .to_encoded_point(true) + .as_bytes(), + ) + } + + fn zeroize_sk_on_drop(_sk: &mut Self::Sk) {} + + fn serialize_sk(sk: &Self::Sk) -> GenericArray { + sk.to_be_bytes() + } + + fn deserialize_sk(bytes: &GenericArray) -> Result { + SecretKey::from_be_bytes(bytes).map_err(|_| InternalError::PointError) + } +} diff --git a/src/key_exchange/group/mod.rs b/src/key_exchange/group/mod.rs index dad51636..95f4526b 100644 --- a/src/key_exchange/group/mod.rs +++ b/src/key_exchange/group/mod.rs @@ -7,37 +7,62 @@ //! Includes the KeGroup trait and definitions for the key exchange groups +mod elliptic_curve; +#[cfg(feature = "ristretto255")] +pub mod ristretto255; +#[cfg(feature = "x25519")] +pub mod x25519; + +use digest::core_api::BlockSizeUser; +use digest::Digest; +use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; use crate::errors::InternalError; /// A group representation for use in the key exchange -pub trait KeGroup: Sized + Clone { +pub trait KeGroup { + /// Public key + type Pk: Clone; /// Length of the public key - type PkLen: ArrayLength + 'static; + type PkLen: ArrayLength; + /// Secret key + type Sk: Clone; /// Length of the secret key - type SkLen: ArrayLength + 'static; + type SkLen: ArrayLength; + + /// Serializes `self` + fn serialize_pk(pk: &Self::Pk) -> GenericArray; /// Return a public key from its fixed-length bytes representation - fn from_pk_slice(element_bits: &GenericArray) -> Result; + fn deserialize_pk(bytes: &GenericArray) -> Result; /// Generate a random secret key - fn random_sk(rng: &mut R) -> GenericArray; + fn random_sk(rng: &mut R) -> Self::Sk; + + /// Hashes a slice of pseudo-random bytes to a scalar + /// + /// # Errors + /// [`InternalError::HashToScalar`] if the `input` is empty or longer then + /// [`u16::MAX`]. + fn hash_to_scalar(input: &[&[u8]], dst: &[u8]) -> Result + where + H: Digest + BlockSizeUser, + H::OutputSize: IsLess + IsLessOrEqual; /// Return a public key from its secret key - fn public_key(sk: &GenericArray) -> Self; + fn public_key(sk: &Self::Sk) -> Self::Pk; + + /// Diffie-Hellman key exchange + fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray; + + /// Zeroize secret key on drop. + fn zeroize_sk_on_drop(sk: &mut Self::Sk); /// Serializes `self` - fn to_arr(&self) -> GenericArray; + fn serialize_sk(sk: &Self::Sk) -> GenericArray; - /// Diffie-Hellman key exchange - fn diffie_hellman(&self, sk: &GenericArray) -> GenericArray; + /// Return a public key from its fixed-length bytes representation + fn deserialize_sk(bytes: &GenericArray) -> Result; } - -#[cfg(feature = "p256")] -pub mod p256; -#[cfg(feature = "ristretto255")] -pub mod ristretto255; -#[cfg(feature = "x25519")] -pub mod x25519; diff --git a/src/key_exchange/group/p256.rs b/src/key_exchange/group/p256.rs deleted file mode 100644 index 50eb9cb7..00000000 --- a/src/key_exchange/group/p256.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache -// License, Version 2.0 found in the LICENSE-APACHE file in the root directory -// of this source tree. - -//! Key Exchange group implementation for p256 - -use generic_array::typenum::{U32, U33}; -use generic_array::GenericArray; -use p256_::elliptic_curve::group::GroupEncoding; -use p256_::elliptic_curve::sec1::ToEncodedPoint; -use p256_::elliptic_curve::{PublicKey, SecretKey}; -use p256_::NistP256; -use rand::{CryptoRng, RngCore}; - -use super::KeGroup; -use crate::errors::InternalError; - -impl KeGroup for PublicKey { - type PkLen = U33; - type SkLen = U32; - - fn from_pk_slice(element_bits: &GenericArray) -> Result { - Self::from_sec1_bytes(element_bits).map_err(|_| InternalError::PointError) - } - - fn random_sk(rng: &mut R) -> GenericArray { - SecretKey::::random(rng).to_be_bytes() - } - - fn public_key(sk: &GenericArray) -> Self { - SecretKey::::from_be_bytes(sk) - .unwrap() - .public_key() - } - - fn to_arr(&self) -> GenericArray { - GenericArray::clone_from_slice(self.to_encoded_point(true).as_bytes()) - } - - fn diffie_hellman(&self, sk: &GenericArray) -> GenericArray { - (self.to_projective() - * SecretKey::::from_be_bytes(sk) - .unwrap() - .to_nonzero_scalar() - .as_ref()) - .to_affine() - .to_bytes() - } -} diff --git a/src/key_exchange/group/ristretto255.rs b/src/key_exchange/group/ristretto255.rs index c4c6ebd7..cf7fe3b8 100644 --- a/src/key_exchange/group/ristretto255.rs +++ b/src/key_exchange/group/ristretto255.rs @@ -10,24 +10,40 @@ use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; -use generic_array::typenum::U32; +use digest::core_api::BlockSizeUser; +use digest::{Digest, OutputSizeUser}; +use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander}; +use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64}; use generic_array::GenericArray; use rand::{CryptoRng, RngCore}; +use voprf::Group; +use zeroize::Zeroize; use super::KeGroup; use crate::errors::InternalError; -impl KeGroup for RistrettoPoint { +/// Implementation for Ristretto255. +// This is necessary because Rust lacks specialization, otherwise we could +// implement `KeGroup` for `voprf::Ristretto255`. +pub struct Ristretto255; + +impl KeGroup for Ristretto255 { + type Pk = RistrettoPoint; type PkLen = U32; + type Sk = Scalar; type SkLen = U32; - fn from_pk_slice(element_bits: &GenericArray) -> Result { - CompressedRistretto::from_slice(element_bits) + fn serialize_pk(pk: &Self::Pk) -> GenericArray { + pk.compress().to_bytes().into() + } + + fn deserialize_pk(bytes: &GenericArray) -> Result { + CompressedRistretto::from_slice(bytes) .decompress() .ok_or(InternalError::PointError) } - fn random_sk(rng: &mut R) -> GenericArray { + fn random_sk(rng: &mut R) -> Self::Sk { loop { let scalar = { #[cfg(not(test))] @@ -47,21 +63,121 @@ impl KeGroup for RistrettoPoint { } }; - if scalar != Scalar::zero() { - break scalar.to_bytes().into(); + if scalar != Scalar::zero() && scalar.is_canonical() { + break scalar; } } } - fn public_key(sk: &GenericArray) -> Self { - RISTRETTO_BASEPOINT_POINT * Scalar::from_bits(*sk.as_ref()) + // Implements the `HashToScalar()` function from + // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4.1 + fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result + where + H: Digest + BlockSizeUser, + H::OutputSize: IsLess + IsLessOrEqual, + { + let mut uniform_bytes = GenericArray::<_, U64>::default(); + ExpandMsgXmd::::expand_message(input, dst, 64) + .map_err(|_| InternalError::HashToScalar)? + .fill_bytes(&mut uniform_bytes); + + Ok(Scalar::from_bytes_mod_order_wide(&uniform_bytes.into())) + } + + fn public_key(sk: &Self::Sk) -> Self::Pk { + RISTRETTO_BASEPOINT_POINT * sk + } + + fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray { + Self::serialize_pk(&(pk * sk)) + } + + fn zeroize_sk_on_drop(sk: &mut Self::Sk) { + sk.zeroize() + } + + fn serialize_sk(sk: &Self::Sk) -> GenericArray { + sk.to_bytes().into() + } + + fn deserialize_sk(bytes: &GenericArray) -> Result { + Scalar::from_canonical_bytes((*bytes).into()).ok_or(InternalError::PointError) + } +} + +#[cfg(feature = "ristretto255_voprf")] +impl voprf::CipherSuite for Ristretto255 { + const ID: u16 = voprf::Ristretto255::ID; + + type Group = ::Group; + + type Hash = ::Hash; +} + +impl Group for Ristretto255 { + type Elem = ::Elem; + + type ElemLen = ::ElemLen; + + type Scalar = ::Scalar; + + type ScalarLen = ::ScalarLen; + + fn hash_to_curve( + input: &[&[u8]], + dst: &[u8], + ) -> voprf::Result + where + ::OutputSize: + IsLess + IsLessOrEqual<::BlockSize>, + { + ::hash_to_curve::(input, dst) + } + + fn hash_to_scalar( + input: &[&[u8]], + dst: &[u8], + ) -> voprf::Result + where + ::OutputSize: + IsLess + IsLessOrEqual<::BlockSize>, + { + ::hash_to_scalar::(input, dst) + } + + fn base_elem() -> Self::Elem { + ::base_elem() + } + + fn identity_elem() -> Self::Elem { + ::identity_elem() + } + + fn serialize_elem(elem: Self::Elem) -> GenericArray { + ::serialize_elem(elem) + } + + fn deserialize_elem(element_bits: &[u8]) -> voprf::Result { + ::deserialize_elem(element_bits) + } + + fn random_scalar(rng: &mut R) -> Self::Scalar { + ::random_scalar(rng) + } + + fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar { + ::invert_scalar(scalar) + } + + fn is_zero_scalar(scalar: Self::Scalar) -> subtle::Choice { + ::is_zero_scalar(scalar) } - fn to_arr(&self) -> GenericArray { - self.compress().to_bytes().into() + fn serialize_scalar(scalar: Self::Scalar) -> GenericArray { + ::serialize_scalar(scalar) } - fn diffie_hellman(&self, sk: &GenericArray) -> GenericArray { - (self * Scalar::from_bits(*sk.as_ref())).to_arr() + fn deserialize_scalar(scalar_bits: &[u8]) -> voprf::Result { + ::deserialize_scalar(scalar_bits) } } diff --git a/src/key_exchange/group/x25519.rs b/src/key_exchange/group/x25519.rs index 18d2067d..690b4d05 100644 --- a/src/key_exchange/group/x25519.rs +++ b/src/key_exchange/group/x25519.rs @@ -7,47 +7,97 @@ //! Key Exchange group implementation for X25519 -use generic_array::typenum::U32; +use curve25519_dalek_3::scalar::Scalar; +use digest::core_api::BlockSizeUser; +use digest::Digest; +use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander}; +use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64}; use generic_array::GenericArray; use rand::{CryptoRng, RngCore}; use x25519_dalek::{PublicKey, StaticSecret}; +use zeroize::Zeroize; use super::KeGroup; use crate::errors::InternalError; +/// Implementation for X25519. +pub struct X25519; + /// The implementation of such a subgroup for Ristretto -impl KeGroup for PublicKey { +impl KeGroup for X25519 { + type Pk = PublicKey; type PkLen = U32; + type Sk = StaticSecret; type SkLen = U32; - fn from_pk_slice(element_bits: &GenericArray) -> Result { - Ok(Self::from(<[u8; 32]>::from(*element_bits))) + fn serialize_pk(pk: &Self::Pk) -> GenericArray { + pk.to_bytes().into() + } + + fn deserialize_pk(bytes: &GenericArray) -> Result { + if **bytes == [0; 32] { + Err(InternalError::PointError) + } else { + Ok(PublicKey::from(<[_; 32]>::from(*bytes))) + } } - fn random_sk(rng: &mut R) -> GenericArray { + fn random_sk(rng: &mut R) -> Self::Sk { let mut scalar_bytes = [0u8; 32]; loop { rng.fill_bytes(&mut scalar_bytes); if scalar_bytes != [0u8; 32] { - break StaticSecret::from(scalar_bytes).to_bytes().into(); + break StaticSecret::from(scalar_bytes); } } } - fn public_key(sk: &GenericArray) -> Self { - Self::from(&StaticSecret::from(<[u8; 32]>::from(*sk))) + // Implements the `HashToScalar()` function from + // https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-4.1 + fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result + where + H: Digest + BlockSizeUser, + H::OutputSize: IsLess + IsLessOrEqual, + { + let mut uniform_bytes = GenericArray::<_, U64>::default(); + ExpandMsgXmd::::expand_message(input, dst, 64) + .map_err(|_| InternalError::HashToScalar)? + .fill_bytes(&mut uniform_bytes); + + Ok(StaticSecret::from( + Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()).to_bytes(), + )) + } + + fn public_key(sk: &Self::Sk) -> Self::Pk { + PublicKey::from(sk) } - fn to_arr(&self) -> GenericArray { - self.to_bytes().into() + fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray { + sk.diffie_hellman(pk).to_bytes().into() } - fn diffie_hellman(&self, sk: &GenericArray) -> GenericArray { - StaticSecret::from(<[u8; 32]>::from(*sk)) - .diffie_hellman(self) - .to_bytes() - .into() + fn zeroize_sk_on_drop(sk: &mut Self::Sk) { + sk.zeroize() + } + + fn serialize_sk(sk: &Self::Sk) -> GenericArray { + sk.to_bytes().into() + } + + fn deserialize_sk(bytes: &GenericArray) -> Result { + if **bytes == [0; 32] { + Err(InternalError::PointError) + } else { + let sk = StaticSecret::from(<[u8; 32]>::from(*bytes)); + + if sk.to_bytes() == **bytes { + Ok(sk) + } else { + Err(InternalError::PointError) + } + } } } diff --git a/src/key_exchange/traits.rs b/src/key_exchange/traits.rs old mode 100755 new mode 100644 index 4e2bfe8b..0889a4f7 --- a/src/key_exchange/traits.rs +++ b/src/key_exchange/traits.rs @@ -10,9 +10,9 @@ use digest::Output; use generic_array::typenum::{IsLess, Le, NonZero, U256}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; -use zeroize::Zeroize; +use zeroize::ZeroizeOnDrop; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfHash}; use crate::errors::ProtocolError; use crate::hash::{Hash, ProxyHash}; use crate::key_exchange::group::KeGroup; @@ -46,17 +46,17 @@ where ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, { - type KE1State: FromBytes + ToBytes + Zeroize + Clone; - type KE2State: FromBytes + ToBytes + Zeroize + Clone; - type KE1Message: FromBytes + ToBytes + Zeroize + Clone; - type KE2Message: FromBytes + ToBytes + Clone; - type KE3Message: FromBytes + ToBytes + Clone; + type KE1State: FromBytes + ToBytes + ZeroizeOnDrop + Clone; + type KE2State: FromBytes + ToBytes + ZeroizeOnDrop + Clone; + type KE1Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone; + type KE2Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone; + type KE3Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone; fn generate_ke1( rng: &mut R, ) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>; - #[allow(clippy::too_many_arguments, clippy::type_complexity)] + #[allow(clippy::too_many_arguments)] fn generate_ke2<'a, 'b, 'c, 'd, R: RngCore + CryptoRng, S: SecretKey>( rng: &mut R, l1_bytes: impl Iterator, @@ -69,7 +69,7 @@ where context: &[u8], ) -> Result, ProtocolError>; - #[allow(clippy::too_many_arguments, clippy::type_complexity)] + #[allow(clippy::too_many_arguments)] fn generate_ke3<'a, 'b, 'c, 'd>( l2_component: impl Iterator, ke2_message: Self::KE2Message, @@ -82,13 +82,10 @@ where context: &[u8], ) -> Result, ProtocolError>; - #[allow(clippy::type_complexity)] fn finish_ke( ke3_message: Self::KE3Message, ke2_state: &Self::KE2State, ) -> Result, ProtocolError>; - - fn ke2_message_size() -> usize; } pub trait FromBytes: Sized { @@ -101,14 +98,13 @@ pub trait ToBytes { fn to_bytes(&self) -> GenericArray; } -#[allow(dead_code)] pub type Ke1StateLen = - <>::KE1State as ToBytes>::Len; + <, CS::KeGroup>>::KE1State as ToBytes>::Len; pub type Ke1MessageLen = - <>::KE1Message as ToBytes>::Len; + <, CS::KeGroup>>::KE1Message as ToBytes>::Len; pub type Ke2StateLen = - <>::KE2State as ToBytes>::Len; + <, CS::KeGroup>>::KE2State as ToBytes>::Len; pub type Ke2MessageLen = - <>::KE2Message as ToBytes>::Len; + <, CS::KeGroup>>::KE2Message as ToBytes>::Len; pub type Ke3MessageLen = - <>::KE3Message as ToBytes>::Len; + <, CS::KeGroup>>::KE3Message as ToBytes>::Len; diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs old mode 100755 new mode 100644 index 65935f18..797bbefd --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -9,7 +9,7 @@ use core::convert::TryFrom; use core::ops::Add; -use derive_where::DeriveWhere; +use derive_where::derive_where; use digest::core_api::BlockSizeUser; use digest::{Digest, Output}; use generic_array::sequence::Concat; @@ -18,6 +18,7 @@ use generic_array::{ArrayLength, GenericArray}; use hkdf::{Hkdf, HkdfExtract}; use hmac::{Hmac, Mac}; use rand::{CryptoRng, RngCore}; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::errors::utils::{check_slice_size, check_slice_size_atleast}; use crate::errors::{InternalError, ProtocolError}; @@ -55,36 +56,63 @@ pub struct TripleDH; #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") + serde( + bound( + deserialize = "KG::Sk: serde_::Deserialize<'de>", + serialize = "KG::Sk: serde_::Serialize", + ), + crate = "serde_" + ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)] pub struct Ke1State { client_e_sk: PrivateKey, client_nonce: GenericArray, } +impl Drop for Ke1State { + fn drop(&mut self) { + self.client_nonce.zeroize(); + } +} + +impl ZeroizeOnDrop for Ke1State {} + /// The first key exchange message #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") + serde( + bound( + deserialize = "KG::Pk: serde_::Deserialize<'de>", + serialize = "KG::Pk: serde_::Serialize", + ), + crate = "serde_" + ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)] +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)] pub struct Ke1Message { pub(crate) client_nonce: GenericArray, pub(crate) client_e_pk: PublicKey, } +impl Drop for Ke1Message { + fn drop(&mut self) { + self.client_nonce.zeroize(); + } +} + +impl ZeroizeOnDrop for Ke1Message {} + /// The server state produced after the second key exchange message #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), serde(bound = "", crate = "serde_") )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] +#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Ke2State where D::Core: ProxyHash, @@ -96,14 +124,41 @@ where session_key: Output, } +impl Drop for Ke2State +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ + fn drop(&mut self) { + self.km3.zeroize(); + self.hashed_transcript.zeroize(); + self.session_key.zeroize(); + } +} + +impl ZeroizeOnDrop for Ke2State +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ +} + /// The second key exchange message #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") + serde( + bound( + deserialize = "KG::Pk: serde_::Deserialize<'de>", + serialize = "KG::Pk: serde_::Serialize", + ), + crate = "serde_" + ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)] pub struct Ke2Message where D::Core: ProxyHash, @@ -115,13 +170,32 @@ where mac: Output, } +impl Drop for Ke2Message +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ + fn drop(&mut self) { + self.server_nonce.zeroize(); + self.mac.zeroize(); + } +} + +impl ZeroizeOnDrop for Ke2Message +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ +} + /// The third key exchange message #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), serde(bound = "", crate = "serde_") )] -#[derive(DeriveWhere)] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Ke3Message where @@ -132,6 +206,25 @@ where mac: Output, } +impl Drop for Ke3Message +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ + fn drop(&mut self) { + self.mac.zeroize(); + } +} + +impl ZeroizeOnDrop for Ke3Message +where + D::Core: ProxyHash, + ::BlockSize: IsLess, + Le<::BlockSize, U256>: NonZero, +{ +} + //////////////////////////////// // High-level Implementations // // ========================== // @@ -210,13 +303,13 @@ where .chain_iter(id_s.into_iter()) .chain_iter(l2_bytes) .chain(server_nonce) - .chain(&server_e_kp.public().to_arr()); + .chain(&server_e_kp.public().to_bytes()); let result = derive_3dh_keys::( TripleDHComponents { pk1: ke1_message.client_e_pk.clone(), sk1: server_e_kp.private().clone(), - pk2: ke1_message.client_e_pk, + pk2: ke1_message.client_e_pk.clone(), sk2: server_s_sk, pk3: client_s_pk, sk3: server_e_kp.private().clone(), @@ -268,7 +361,7 @@ where .chain_iter(serialized_credential_request) .chain_iter(id_s) .chain_iter(l2_component) - .chain_iter(ke2_message.to_bytes_without_info_or_mac()); + .chain(ke2_message.to_bytes_without_mac()); let result = derive_3dh_keys::>( TripleDHComponents { @@ -322,10 +415,6 @@ where Ok(ke2_state.session_key.clone()) } - - fn ke2_message_size() -> usize { - NonceLen::USIZE + ::PkLen::USIZE + OutputSize::::USIZE - } } ///////////////////////// @@ -489,7 +578,7 @@ impl FromBytes for Ke1State { let checked_bytes = check_slice_size_atleast(bytes, key_len + nonce_len, "ke1_state")?; Ok(Self { - client_e_sk: PrivateKey::from_bytes(&checked_bytes[..key_len])?, + client_e_sk: PrivateKey::deserialize(&checked_bytes[..key_len])?, client_nonce: GenericArray::clone_from_slice( &checked_bytes[key_len..key_len + nonce_len], ), @@ -506,7 +595,7 @@ where type Len = Sum; fn to_bytes(&self) -> GenericArray { - self.client_e_sk.to_arr().concat(self.client_nonce) + self.client_e_sk.serialize().concat(self.client_nonce) } } @@ -521,7 +610,7 @@ impl FromBytes for Ke1Message { Ok(Self { client_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]), - client_e_pk: PublicKey::from_bytes(&checked_nonce[nonce_len..])?, + client_e_pk: PublicKey::deserialize(&checked_nonce[nonce_len..])?, }) } } @@ -535,7 +624,7 @@ where type Len = Sum; fn to_bytes(&self) -> GenericArray { - self.client_nonce.concat(self.client_e_pk.to_arr()) + self.client_nonce.concat(self.client_e_pk.to_bytes()) } } @@ -602,13 +691,11 @@ where )?; // Check the public key bytes - let server_e_pk = KeyPair::::check_public_key(PublicKey::from_bytes( - &unchecked_server_e_pk[..key_len], - )?)?; + let server_e_pk = PublicKey::deserialize(&unchecked_server_e_pk[..key_len])?; Ok(Self { server_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]), - server_e_pk: PublicKey::from_bytes(&server_e_pk)?, + server_e_pk, mac: GenericArray::clone_from_slice(checked_mac), }) } @@ -628,7 +715,7 @@ where fn to_bytes(&self) -> GenericArray { self.server_nonce - .concat(self.server_e_pk.to_arr()) + .concat(self.server_e_pk.to_bytes()) .concat(self.mac.clone()) } } @@ -638,9 +725,11 @@ where D::Core: ProxyHash, ::BlockSize: IsLess, Le<::BlockSize, U256>: NonZero, + NonceLen: Add, + Sum: ArrayLength, { - fn to_bytes_without_info_or_mac(&self) -> impl Iterator { - [self.server_nonce.as_slice(), self.server_e_pk.as_slice()].into_iter() + fn to_bytes_without_mac(&self) -> GenericArray> { + self.server_nonce.concat(self.server_e_pk.to_bytes()) } } diff --git a/src/keypair.rs b/src/keypair.rs index 40fa8c87..3c133051 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -9,16 +9,14 @@ #![allow(unsafe_code)] -use core::ops::Deref; - -use derive_where::DeriveWhere; -use generic_array::typenum::Unsigned; +use derive_where::derive_where; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; -use zeroize::Zeroize; +use zeroize::ZeroizeOnDrop; use crate::errors::{InternalError, ProtocolError}; use crate::key_exchange::group::KeGroup; +use crate::serialization::GenericArrayExt; /// A Keypair trait with public-private verification #[cfg_attr( @@ -26,15 +24,14 @@ use crate::key_exchange::group::KeGroup; derive(serde_::Deserialize, serde_::Serialize), serde( bound( - deserialize = "S: serde_::Deserialize<'de>", - serialize = "S: serde_::Serialize" + deserialize = "KG::Pk: serde_::Deserialize<'de>, S: serde_::Deserialize<'de>", + serialize = "KG::Pk: serde_::Serialize, S: serde_::Serialize" ), crate = "serde_" ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Zeroize(drop))] -#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; S)] +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk, S)] pub struct KeyPair = PrivateKey> { pk: PublicKey, sk: S, @@ -51,14 +48,6 @@ impl> KeyPair { &self.sk } - /// Check whether a public key is valid. This is meant to be applied on - /// material provided through the network which fits the key representation - /// (i.e. can be mapped to a curve point), but presents some risk - e.g. - /// small subgroup check - pub(crate) fn check_public_key(key: PublicKey) -> Result, InternalError> { - KG::from_pk_slice(GenericArray::from_slice(&key.0)).map(|_| key) - } - /// Obtains a KeyPair from a slice representing the private key pub fn from_private_key_slice(input: &[u8]) -> Result> { Self::from_private_key(S::deserialize(input)?) @@ -77,14 +66,18 @@ impl KeyPair { let sk = KG::random_sk(rng); let pk = KG::public_key(&sk); Self { - pk: PublicKey(Key(pk.to_arr())), - sk: PrivateKey(Key(sk)), + pk: PublicKey(pk), + sk: PrivateKey(sk), } } } #[cfg(test)] -impl KeyPair { +impl KeyPair +where + KG::Pk: std::fmt::Debug, + KG::Sk: std::fmt::Debug, +{ /// Test-only strategy returning a proptest Strategy based on /// generate_random fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy { @@ -104,70 +97,39 @@ impl KeyPair { } } -/// A minimalist key type built around a \[u8; 32\] -#[cfg_attr( - feature = "serde", - derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") -)] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] -pub struct Key>(GenericArray); - -impl> Deref for Key { - type Target = GenericArray; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// Don't make it implement SizedBytes so that it's not constructible outside of -// this module. -impl> Key { - /// Convert to bytes - pub fn to_arr(&self) -> GenericArray { - self.0.clone() - } -} - /// Wrapper around a Key to enforce that it's a private one. #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") + serde( + bound( + deserialize = "KG::Sk: serde_::Deserialize<'de>", + serialize = "KG::Sk: serde_::Serialize" + ), + crate = "serde_" + ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] -pub struct PrivateKey(Key); +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)] +pub struct PrivateKey(KG::Sk); -// This can't be derived because of the use of a generic parameter -impl Deref for PrivateKey { - type Target = Key; - - fn deref(&self) -> &Self::Target { - &self.0 +impl Drop for PrivateKey { + fn drop(&mut self) { + KG::zeroize_sk_on_drop(&mut self.0) } } +impl ZeroizeOnDrop for PrivateKey {} + impl PrivateKey { /// Convert from bytes - pub fn from_arr(key_bytes: GenericArray) -> Self { - PrivateKey(Key(key_bytes)) - } - - /// Convert from slice - pub fn from_bytes(key_bytes: &[u8]) -> Result { - if key_bytes.len() == KG::SkLen::USIZE { - Ok(Self::from_arr(GenericArray::from_slice(key_bytes).clone())) - } else { - Err(InternalError::InvalidByteSequence) - } + pub fn from_bytes(key_bytes: &GenericArray) -> Result { + KG::deserialize_sk(key_bytes).map(Self) } } /// A trait specifying the requirements for a private key container -pub trait SecretKey: Clone + Sized + Zeroize { +pub trait SecretKey: Clone + Sized { /// Custom error type that can be passed down to `InternalError::Custom` type Error; /// Serialization size in bytes. @@ -197,20 +159,19 @@ impl SecretKey for PrivateKey { &self, pk: PublicKey, ) -> Result, InternalError> { - let pk = KG::from_pk_slice(&pk)?; - Ok(pk.diffie_hellman(self)) + Ok(KG::diffie_hellman(&pk.0, &self.0)) } fn public_key(&self) -> Result, InternalError> { - Ok(PublicKey(Key(KG::public_key(&self.0).to_arr()))) + Ok(PublicKey(KG::public_key(&self.0))) } fn serialize(&self) -> GenericArray { - self.to_arr() + KG::serialize_sk(&self.0) } fn deserialize(input: &[u8]) -> Result { - PrivateKey::from_bytes(input).map_err(InternalError::from) + GenericArray::try_from_slice(input).and_then(Self::from_bytes) } } @@ -218,93 +179,54 @@ impl SecretKey for PrivateKey { #[cfg_attr( feature = "serde", derive(serde_::Deserialize, serde_::Serialize), - serde(bound = "", crate = "serde_") + serde( + bound( + deserialize = "KG::Pk: serde_::Deserialize<'de>", + serialize = "KG::Pk: serde_::Serialize" + ), + crate = "serde_" + ) )] -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] -pub struct PublicKey(Key); - -impl Deref for PublicKey { - type Target = Key; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)] +pub struct PublicKey(KG::Pk); impl PublicKey { /// Convert from bytes - pub fn from_arr(key_bytes: GenericArray) -> Self { - Self(Key(key_bytes)) + pub fn from_bytes(key_bytes: &GenericArray) -> Result { + KG::deserialize_pk(key_bytes).map(Self) + } + + /// Convert to bytes + pub fn to_bytes(&self) -> GenericArray { + KG::serialize_pk(&self.0) } /// Convert from slice - pub fn from_bytes(key_bytes: &[u8]) -> Result { - if key_bytes.len() == KG::PkLen::USIZE { - Ok(Self::from_arr(GenericArray::from_slice(key_bytes).clone())) - } else { - Err(InternalError::InvalidByteSequence) - } + pub fn deserialize(input: &[u8]) -> Result { + GenericArray::try_from_slice(input).and_then(Self::from_bytes) } } #[cfg(test)] mod tests { - use core::slice::from_raw_parts; - use std::vec; - - use generic_array::typenum::Unsigned; use rand::rngs::OsRng; use super::*; use crate::errors::*; + use crate::util; #[test] - fn test_zeroize_key() -> Result<(), ProtocolError> { - fn inner() -> Result<(), ProtocolError> { - let key_len = G::PkLen::USIZE; - let mut key = Key::(GenericArray::clone_from_slice(&vec![1u8; key_len])); - let ptr = key.as_ptr(); - - Zeroize::zeroize(&mut key); - - let bytes = unsafe { from_raw_parts(ptr, key_len) }; - assert!(bytes.iter().all(|&x| x == 0)); - - Ok(()) - } - - #[cfg(feature = "ristretto255")] - inner::()?; - #[cfg(feature = "p256")] - inner::()?; - - Ok(()) - } - - #[test] - fn test_zeroize_keypair() { + fn test_zeroize_key() { fn inner() { let mut rng = OsRng; - let mut keypair = KeyPair::::generate_random(&mut rng); - let pk_ptr = keypair.pk.as_ptr(); - let sk_ptr = keypair.sk.as_ptr(); - let pk_len = G::PkLen::USIZE; - let sk_len = G::SkLen::USIZE; - - Zeroize::zeroize(&mut keypair); - - let pk_bytes = unsafe { from_raw_parts(pk_ptr, pk_len) }; - let sk_bytes = unsafe { from_raw_parts(sk_ptr, sk_len) }; - - assert!(pk_bytes.iter().all(|&x| x == 0)); - assert!(sk_bytes.iter().all(|&x| x == 0)); + let mut key = PrivateKey::(G::random_sk(&mut rng)); + util::test_zeroize_on_drop(&mut key); } #[cfg(feature = "ristretto255")] - inner::(); - #[cfg(feature = "p256")] - inner::(); + inner::(); + inner::<::p256::NistP256>(); } macro_rules! test { @@ -317,12 +239,6 @@ mod tests { use super::*; proptest! { - #[test] - fn check(kp in KeyPair::<$point>::uniform_keypair_strategy()) { - let pk = kp.public(); - prop_assert!(KeyPair::<$point>::check_public_key(pk.clone()).is_ok()); - } - #[test] fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) { let pk = kp.public(); @@ -342,10 +258,10 @@ mod tests { #[test] fn private_key_slice(kp in KeyPair::<$point>::uniform_keypair_strategy()) { - let sk_bytes = kp.private().to_vec(); + let sk_bytes = kp.private().serialize().to_vec(); let kp2 = KeyPair::<$point>::from_private_key_slice(&sk_bytes)?; - let kp2_private_bytes = kp2.private().to_vec(); + let kp2_private_bytes = kp2.private().serialize().to_vec(); prop_assert_eq!(sk_bytes, kp2_private_bytes); } @@ -355,16 +271,11 @@ mod tests { } #[cfg(feature = "ristretto255")] - test!(ristretto, curve25519_dalek::ristretto::RistrettoPoint); - #[cfg(feature = "p256")] - test!(p256, p256_::PublicKey); + test!(ristretto, crate::Ristretto255); + test!(p256, ::p256::NistP256); #[test] fn remote_key() { - #[cfg(feature = "ristretto255")] - use curve25519_dalek::ristretto::RistrettoPoint as KeCurve; - #[cfg(not(feature = "ristretto255"))] - use p256_::PublicKey as KeCurve; use rand::rngs::OsRng; use crate::{ @@ -379,19 +290,20 @@ mod tests { impl CipherSuite for Default { #[cfg(feature = "ristretto255")] - type OprfGroup = KeCurve; + type OprfGroup = crate::Ristretto255; #[cfg(not(feature = "ristretto255"))] - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = KeCurve; - type KeyExchange = crate::key_exchange::tripledh::TripleDH; + type OprfGroup = ::p256::NistP256; #[cfg(feature = "ristretto255")] - type Hash = sha2::Sha512; + type KeGroup = crate::Ristretto255; #[cfg(not(feature = "ristretto255"))] - type Hash = sha2::Sha256; + type KeGroup = ::p256::NistP256; + type KeyExchange = crate::key_exchange::tripledh::TripleDH; type SlowHash = crate::slow_hash::NoOpHash; } - #[derive(Clone, Zeroize)] + type KeCurve = ::KeGroup; + + #[derive(Clone)] struct RemoteKey(PrivateKey); impl SecretKey for RemoteKey { @@ -422,7 +334,7 @@ mod tests { const PASSWORD: &str = "password"; let sk = KeCurve::random_sk(&mut OsRng); - let sk = RemoteKey(PrivateKey(Key(sk))); + let sk = RemoteKey(PrivateKey(sk)); let keypair = KeyPair::from_private_key(sk).unwrap(); let server_setup = ServerSetup::::new_with_key(&mut OsRng, keypair); diff --git a/src/lib.rs b/src/lib.rs index 37645129..6038bbf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ //! //! ### Minimum Supported Rust Version //! -//! Rust **1.56** or higher. +//! Rust **1.57** or higher. //! //! # Overview //! @@ -33,10 +33,9 @@ //! use opaque_ke::CipherSuite; //! struct Default; //! impl CipherSuite for Default { -//! type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! type OprfGroup = opaque_ke::Ristretto255; +//! type KeGroup = opaque_ke::Ristretto255; //! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! type Hash = sha2::Sha512; //! type SlowHash = opaque_ke::slow_hash::NoOpHash; //! } //! ``` @@ -59,18 +58,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! use rand::rngs::OsRng; @@ -110,18 +107,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! use opaque_ke::ClientRegistration; @@ -150,18 +145,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -199,18 +192,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -249,18 +240,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -304,18 +293,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -343,18 +330,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -408,18 +393,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -466,18 +449,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -564,18 +545,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -663,18 +642,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -746,18 +723,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -796,18 +771,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -857,18 +830,16 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # use rand::{rngs::OsRng, RngCore}; @@ -955,27 +926,25 @@ //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; -//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; +//! # type OprfGroup = opaque_ke::Ristretto255; +//! # type KeGroup = opaque_ke::Ristretto255; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha512; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { -//! # type OprfGroup = p256_::ProjectivePoint; -//! # type KeGroup = p256_::PublicKey; +//! # type OprfGroup = p256::NistP256; +//! # type KeGroup = p256::NistP256; //! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; -//! # type Hash = sha2::Sha256; //! # type SlowHash = opaque_ke::slow_hash::NoOpHash; //! # } //! # #[derive(Debug)] //! # struct YourRemoteKeyError; -//! # #[derive(Clone, Zeroize)] -//! # struct YourRemoteKey(PrivateKey<::KeGroup>); +//! # #[derive(Clone)] +//! # struct YourRemoteKey(<::KeGroup as KeGroup>::Sk); //! # impl YourRemoteKey { //! # fn diffie_hellman(&self, pk: &[u8]) -> Result::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { todo!() } -//! # fn public_key(&self) -> Result::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(GenericArray::default()) } +//! # fn public_key(&self) -> Result::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(<::KeGroup>::serialize_pk(&<::KeGroup>::public_key(&self.0))) } //! # } //! impl SecretKey<::KeGroup> for YourRemoteKey { //! type Error = YourRemoteKeyError; @@ -985,14 +954,13 @@ //! &self, //! pk: PublicKey<::KeGroup>, //! ) -> Result::KeGroup as KeGroup>::PkLen>, InternalError> { -//! YourRemoteKey::diffie_hellman(self, &pk.to_arr()).map_err(InternalError::Custom) +//! YourRemoteKey::diffie_hellman(self, &pk.to_bytes()).map_err(InternalError::Custom) //! } //! //! fn public_key( //! &self //! ) -> Result::KeGroup>, InternalError> { -//! YourRemoteKey::public_key(self).map(PublicKey::from_arr) -//! .map_err(InternalError::Custom) +//! PublicKey::from_bytes(&YourRemoteKey::public_key(self).map_err(InternalError::Custom)?).map_err(InternalError::into_custom) //! } //! //! fn serialize(&self) -> GenericArray { @@ -1006,7 +974,7 @@ //! } //! } //! -//! # let remote_key = YourRemoteKey(PrivateKey::from_arr(GenericArray::default())); +//! # let remote_key = YourRemoteKey(<::KeGroup>::random_sk(&mut OsRng)); //! let keypair = KeyPair::from_private_key(remote_key).unwrap(); //! let server_setup = ServerSetup::::new_with_key(&mut OsRng, keypair); //! ``` @@ -1032,27 +1000,26 @@ //! `ristretto255_fiat_u32`. Any `ristretto255_*` backend feature will enable //! the `ristretto255` feature, which can be used too, but keep in mind that //! `curve25519-dalek` will fail to compile without a selected backend. This -//! enables the use of `curve25519_dalek::ristretto::RistrettoPoint` as a -//! `KeGroup` and `OprfGroup`. +//! enables the use of [`Ristretto255`] as a `KeGroup` and `OprfGroup`. //! //! - The `x25519` feature is similar to the `ristretto255` feature and requires //! to select a backend like `x25519_u64`, other backends are the same as in -//! `ristretto255_*`. This enables `x25519_dalek::PublicKey` as a `KeGroup`. +//! `ristretto255_*`. This enables [`X25519`] as a `KeGroup`. //! //! - The `ristretto255_simd` feature is re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) //! and enables parallel formulas, using either AVX2 or AVX512-IFMA. This will //! automatically enable the `ristretto255_u64` feature and requires Rust //! nightly. //! -//! - The `p256` feature enables the use of `p256::PublicKey` as a `KeGroup` and -//! `p256::ProjectivePoint` as a `OprfGroup` for `CipherSuite`. Note that this -//! is currently an experimental feature ⚠️, and is not yet ready for -//! production use. +//! - The `p256` feature enables the use of [`p256::NistP256`] as a `KeGroup` +//! and a `OprfGroup` for `CipherSuite`. //! //! - The `bench` feature is used only for running performance benchmarks for //! this implementation. +//! +//! [`p256::NistP256`]: https://docs.rs/p256/latest/p256/struct.NistP256.html -#![deny(unsafe_code)] +#![cfg_attr(not(test), deny(unsafe_code))] #![no_std] #![warn(clippy::cargo, missing_docs)] #![allow(clippy::multiple_crate_versions, type_alias_bounds)] @@ -1074,6 +1041,7 @@ mod messages; mod opaque; mod serialization; pub mod slow_hash; +mod util; #[cfg(test)] mod tests; @@ -1083,6 +1051,10 @@ mod tests; pub use ciphersuite::CipherSuite; pub use rand; +#[cfg(feature = "ristretto255")] +pub use crate::key_exchange::group::ristretto255::Ristretto255; +#[cfg(feature = "x25519")] +pub use crate::key_exchange::group::x25519::X25519; pub use crate::messages::{ CredentialFinalization, CredentialFinalizationLen, CredentialRequest, CredentialRequestLen, CredentialResponse, CredentialResponseLen, RegistrationRequest, RegistrationRequestLen, diff --git a/src/messages.rs b/src/messages.rs old mode 100755 new mode 100644 index c0719977..282e3f6c --- a/src/messages.rs +++ b/src/messages.rs @@ -9,26 +9,28 @@ use core::ops::Add; -use derive_where::DeriveWhere; +use derive_where::derive_where; use digest::core_api::{BlockSizeUser, CoreProxy}; -use digest::Output; +use digest::{Output, OutputSizeUser}; use generic_array::sequence::Concat; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U256}; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U256}; use generic_array::{ArrayLength, GenericArray}; use rand::{CryptoRng, RngCore}; +use subtle::ConstantTimeEq; use voprf::Group; +use zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::{Envelope, EnvelopeLen}; use crate::errors::utils::{check_slice_size, check_slice_size_atleast}; use crate::errors::ProtocolError; -use crate::hash::{OutputSize, ProxyHash}; +use crate::hash::{Hash, OutputSize, ProxyHash}; use crate::key_exchange::group::KeGroup; use crate::key_exchange::traits::{ FromBytes, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, ToBytes, }; use crate::key_exchange::tripledh::NonceLen; -use crate::keypair::{KeyPair, PublicKey, SecretKey}; +use crate::keypair::{PublicKey, SecretKey}; use crate::opaque::{MaskedResponse, MaskedResponseLen, ServerSetup}; //////////////////////////// @@ -37,34 +39,38 @@ use crate::opaque::{MaskedResponse, MaskedResponseLen, ServerSetup}; //////////////////////////// /// The message sent by the client to the server, to initiate registration -#[derive(DeriveWhere)] #[derive_where(Clone)] -#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; CS::OprfGroup)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement)] pub struct RegistrationRequest where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// blinded password information - pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) blinded_element: voprf::BlindedElement, } impl_serialize_and_deserialize_for!(RegistrationRequest); /// The answer sent by the server to the user, upon reception of the /// registration attempt -#[derive(DeriveWhere)] #[derive_where(Clone)] -#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; CS::OprfGroup)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, ::Pk)] pub struct RegistrationResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The server's oprf output - pub(crate) evaluation_element: voprf::EvaluationElement, + pub(crate) evaluation_element: voprf::EvaluationElement, /// Server's static public key pub(crate) server_s_pk: PublicKey, } @@ -73,101 +79,133 @@ impl_serialize_and_deserialize_for!( RegistrationResponse where // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, ); /// The final message from the client, containing sealed cryptographic /// identifiers -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] +#[derive_where(Clone)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk)] pub struct RegistrationUpload where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The "envelope" generated by the user, containing sealed cryptographic /// identifiers pub(crate) envelope: Envelope, /// The masking key used to mask the envelope - pub(crate) masking_key: Output, + pub(crate) masking_key: Output>, /// The user's public key pub(crate) client_s_pk: PublicKey, } +impl Drop for RegistrationUpload +where + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + fn drop(&mut self) { + self.masking_key.zeroize(); + } +} + +impl ZeroizeOnDrop for RegistrationUpload +where + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ +} + impl_serialize_and_deserialize_for!( RegistrationUpload where // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength | Add>, RegistrationUploadLen: ArrayLength, ); /// The message sent by the user to the server, to initiate registration -#[derive(DeriveWhere)] -#[derive_where(Clone, Zeroize)] +#[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( Debug, Eq, Hash, PartialEq; - CS::OprfGroup, - >::KE1Message, + voprf::BlindedElement, + , CS::KeGroup>>::KE1Message, )] pub struct CredentialRequest where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - pub(crate) blinded_element: voprf::BlindedElement, - pub(crate) ke1_message: >::KE1Message, + pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) ke1_message: , CS::KeGroup>>::KE1Message, } impl_serialize_and_deserialize_for!( CredentialRequest where // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, ); /// The answer sent by the server to the user, upon reception of the login /// attempt -#[derive(DeriveWhere)] #[derive_where(Clone)] #[derive_where( Debug, Eq, Hash, PartialEq; - CS::OprfGroup, - >::KE2Message, + voprf::EvaluationElement, + , CS::KeGroup>>::KE2Message, )] pub struct CredentialResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// the server's oprf output - pub(crate) evaluation_element: voprf::EvaluationElement, + pub(crate) evaluation_element: voprf::EvaluationElement, pub(crate) masking_nonce: GenericArray, pub(crate) masked_response: MaskedResponse, - pub(crate) ke2_message: >::KE2Message, + pub(crate) ke2_message: , CS::KeGroup>>::KE2Message, } impl_serialize_and_deserialize_for!( CredentialResponse where // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength | Add>, CredentialResponseWithoutKeLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: + NonceLen: Add>>, + Sum>>: ArrayLength | Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message @@ -177,19 +215,21 @@ impl_serialize_and_deserialize_for!( /// The answer sent by the client to the server, upon reception of the sealed /// envelope -#[derive(DeriveWhere)] #[derive_where(Clone)] #[derive_where( Debug, Eq, Hash, PartialEq; - >::KE3Message, + , CS::KeGroup>>::KE3Message, )] pub struct CredentialFinalization where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - pub(crate) ke3_message: >::KE3Message, + pub(crate) ke3_message: , CS::KeGroup>>::KE3Message, } impl_serialize_and_deserialize_for!(CredentialFinalization); @@ -200,25 +240,26 @@ impl_serialize_and_deserialize_for!(CredentialFinalization); //////////////////////////////// /// Length of [`RegistrationRequest`] in bytes for serialization. -pub type RegistrationRequestLen = ::ElemLen; +pub type RegistrationRequestLen = as Group>::ElemLen; impl RegistrationRequest where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Only used for testing purposes #[cfg(test)] - pub fn get_blinded_element_for_testing( - &self, - ) -> voprf::BlindedElement { + pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { self.blinded_element.clone() } /// Serialization into bytes pub fn serialize(&self) -> GenericArray> { - self.blinded_element.value().to_arr() + as Group>::serialize_elem(self.blinded_element.value()) } /// Deserialization from bytes @@ -231,38 +272,37 @@ where /// Length of [`RegistrationResponse`] in bytes for serialization. pub type RegistrationResponseLen = - Sum<::ElemLen, ::PkLen>; + Sum< as Group>::ElemLen, ::PkLen>; impl RegistrationResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, { - self.evaluation_element - .value() - .to_arr() - .concat(self.server_s_pk.to_arr()) + as Group>::serialize_elem(self.evaluation_element.value()) + .concat(self.server_s_pk.to_bytes()) } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::USIZE; + let elem_len = as Group>::ElemLen::USIZE; let key_len = ::PkLen::USIZE; let checked_slice = check_slice_size(input, elem_len + key_len, "registration_response_bytes")?; // Ensure that public key is valid - let server_s_pk = KeyPair::::check_public_key(PublicKey::from_bytes( - &checked_slice[elem_len..], - )?)?; + let server_s_pk = PublicKey::deserialize(&checked_slice[elem_len..])?; Ok(Self { evaluation_element: voprf::EvaluationElement::deserialize(&checked_slice[..elem_len])?, @@ -273,7 +313,7 @@ where #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the /// reflection error case - pub fn set_evaluation_element_for_testing(&self, beta: CS::OprfGroup) -> Self { + pub fn set_evaluation_element_for_testing(&self, beta: as Group>::Elem) -> Self { Self { evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), server_s_pk: self.server_s_pk.clone(), @@ -283,28 +323,31 @@ where /// Length of [`RegistrationUpload`] in bytes for serialization. pub type RegistrationUploadLen = - Sum::PkLen, OutputSize>, EnvelopeLen>; + Sum::PkLen, OutputSize>>, EnvelopeLen>; impl RegistrationUpload where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { self.client_s_pk - .to_arr() + .to_bytes() .concat(self.masking_key.clone()) .concat(self.envelope.serialize()) } @@ -312,7 +355,7 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let key_len = ::PkLen::USIZE; - let hash_len = OutputSize::::USIZE; + let hash_len = OutputSize::>::USIZE; let checked_slice = check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?; let envelope = Envelope::::deserialize(&checked_slice[key_len + hash_len..])?; @@ -321,9 +364,7 @@ where masking_key: GenericArray::clone_from_slice( &checked_slice[key_len..key_len + hash_len], ), - client_s_pk: KeyPair::::check_public_key(PublicKey::from_bytes( - &checked_slice[..key_len], - )?)?, + client_s_pk: PublicKey::deserialize(&checked_slice[..key_len])?, }) } @@ -332,7 +373,7 @@ where rng: &mut R, server_setup: &ServerSetup, ) -> Self { - let mut masking_key = Output::::default(); + let mut masking_key = Output::>::default(); rng.fill_bytes(&mut masking_key); Self { @@ -345,29 +386,30 @@ where /// Length of [`CredentialRequest`] in bytes for serialization. pub type CredentialRequestLen = - Sum<::ElemLen, Ke1MessageLen>; + Sum< as Group>::ElemLen, Ke1MessageLen>; impl CredentialRequest where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, { - self.blinded_element - .value() - .to_arr() + as Group>::serialize_elem(self.blinded_element.value()) .concat(self.ke1_message.to_bytes()) } pub(crate) fn serialize_iter<'a>( - blinded_element: &'a GenericArray::ElemLen>, + blinded_element: &'a GenericArray as Group>::ElemLen>, ke1_message: &'a GenericArray>, ) -> impl Iterator { [blinded_element.as_slice(), ke1_message].into_iter() @@ -375,23 +417,22 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::USIZE; + let elem_len = as Group>::ElemLen::USIZE; let checked_slice = check_slice_size_atleast(input, elem_len, "login_first_message_bytes")?; // Check that the message is actually containing an element of the correct // subgroup - let blinded_element = voprf::BlindedElement::::deserialize( - &checked_slice[..elem_len], - )?; + let blinded_element = + voprf::BlindedElement::::deserialize(&checked_slice[..elem_len])?; // Throw an error if the identity group element is encountered - if blinded_element.value().is_identity() { + if bool::from( as Group>::identity_elem().ct_eq(&blinded_element.value())) { return Err(ProtocolError::IdentityGroupElementError); } let ke1_message = - >::KE1Message::from_bytes( + , CS::KeGroup>>::KE1Message::from_bytes( &checked_slice[elem_len..], )?; @@ -403,9 +444,7 @@ where /// Only used for testing purposes #[cfg(test)] - pub fn get_blinded_element_for_testing( - &self, - ) -> voprf::BlindedElement { + pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { self.blinded_element.clone() } } @@ -415,40 +454,42 @@ pub type CredentialResponseLen = Sum, Ke2MessageLen>; pub(crate) type CredentialResponseWithoutKeLen = - Sum::ElemLen, NonceLen>, MaskedResponseLen>; + Sum as Group>::ElemLen, NonceLen>, MaskedResponseLen>; impl CredentialResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, CredentialResponseLen: ArrayLength, { - self.evaluation_element - .value() - .to_arr() + as Group>::serialize_elem(self.evaluation_element.value()) .concat(self.masking_nonce) .concat(self.masked_response.serialize()) .concat(self.ke2_message.to_bytes()) } pub(crate) fn serialize_without_ke<'a>( - beta: &'a GenericArray::ElemLen>, + beta: &'a GenericArray as Group>::ElemLen>, masking_nonce: &'a GenericArray, masked_response: &'a MaskedResponse, ) -> impl Iterator { @@ -459,12 +500,12 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let elem_len = ::ElemLen::USIZE; + let elem_len = as Group>::ElemLen::USIZE; let key_len = ::PkLen::USIZE; - let nonce_len: usize = 32; + let nonce_len = NonceLen::USIZE; let envelope_len = Envelope::::len(); let masked_response_len = key_len + envelope_len; - let ke2_message_len = CS::KeyExchange::ke2_message_size(); + let ke2_message_len = Ke2MessageLen::::USIZE; let checked_slice = check_slice_size_atleast( input, @@ -476,10 +517,11 @@ where // subgroup let beta_bytes = &checked_slice[..elem_len]; let evaluation_element = - voprf::EvaluationElement::::deserialize(beta_bytes)?; + voprf::EvaluationElement::::deserialize(beta_bytes)?; // Throw an error if the identity group element is encountered - if evaluation_element.value().is_identity() { + if bool::from( as Group>::identity_elem().ct_eq(&evaluation_element.value())) + { return Err(ProtocolError::IdentityGroupElementError); } @@ -489,7 +531,7 @@ where &checked_slice[elem_len + nonce_len..elem_len + nonce_len + masked_response_len], ); let ke2_message = - >::KE2Message::from_bytes( + , CS::KeGroup>>::KE2Message::from_bytes( &checked_slice[elem_len + nonce_len + masked_response_len..], )?; @@ -504,7 +546,7 @@ where #[cfg(test)] /// Only used for tests, where we can set the beta value to test for the /// reflection error case - pub fn set_evaluation_element_for_testing(&self, beta: CS::OprfGroup) -> Self { + pub fn set_evaluation_element_for_testing(&self, beta: as Group>::Elem) -> Self { Self { evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), masking_nonce: self.masking_nonce, @@ -519,9 +561,12 @@ pub type CredentialFinalizationLen = Ke3MessageLen; impl CredentialFinalization where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> { @@ -531,7 +576,9 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { let ke3_message = - >::KE3Message::from_bytes(input)?; + , CS::KeGroup>>::KE3Message::from_bytes( + input, + )?; Ok(Self { ke3_message }) } } diff --git a/src/opaque.rs b/src/opaque.rs old mode 100755 new mode 100644 index d3f3911c..03ccbae3 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -7,21 +7,20 @@ //! Provides the main OPAQUE API -use core::marker::PhantomData; use core::ops::Add; -use derive_where::DeriveWhere; +use derive_where::derive_where; use digest::core_api::{BlockSizeUser, CoreProxy}; -use digest::Output; +use digest::{Output, OutputSizeUser}; use generic_array::sequence::Concat; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U2, U256}; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U2, U256}; use generic_array::{ArrayLength, GenericArray}; use hkdf::{Hkdf, HkdfExtract}; use rand::{CryptoRng, RngCore}; use subtle::ConstantTimeEq; use voprf::Group; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::{Envelope, EnvelopeLen}; use crate::errors::utils::check_slice_size; use crate::errors::{InternalError, ProtocolError}; @@ -61,126 +60,137 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair"; derive(serde_::Deserialize, serde_::Serialize), serde( bound( - deserialize = "KeyPair: serde_::Deserialize<'de>", - serialize = "KeyPair: serde_::Serialize" + deserialize = "::Pk: serde_::Deserialize<'de>, ::Sk: serde_::Deserialize<'de>, S: serde_::Deserialize<'de>", + serialize = "::Pk: serde_::Serialize, ::Sk: serde_::Serialize, S: serde_::Serialize" ), crate = "serde_" ) )] -#[derive(DeriveWhere)] #[derive_where(Clone)] -#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; S)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk, ::Sk, S)] pub struct ServerSetup< CS: CipherSuite, S: SecretKey = PrivateKey<::KeGroup>, > where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - oprf_seed: Output, + oprf_seed: Output>, keypair: KeyPair, pub(crate) fake_keypair: KeyPair, } /// The state elements the client holds to register itself -#[derive(DeriveWhere)] -#[derive_where(Clone, Zeroize(drop))] +#[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( Debug, Eq, Hash, PartialEq; - voprf::NonVerifiableClient, - voprf::BlindedElement, + voprf::NonVerifiableClient, + voprf::BlindedElement, )] pub struct ClientRegistration where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - pub(crate) oprf_client: voprf::NonVerifiableClient, - pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) oprf_client: voprf::NonVerifiableClient, + pub(crate) blinded_element: voprf::BlindedElement, } impl_serialize_and_deserialize_for!( ClientRegistration where // ClientRegistration: KgSk + KgPk - ::ScalarLen: Add<::ElemLen>, + as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, ); /// The state elements the server holds to record a registration -#[derive(DeriveWhere)] -#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))] -pub struct ServerRegistration(RegistrationUpload) +#[derive_where(Clone, ZeroizeOnDrop)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk)] +pub struct ServerRegistration(pub(crate) RegistrationUpload) where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero; + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero; impl_serialize_and_deserialize_for!( ServerRegistration where // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength | Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload ); /// The state elements the client holds to perform a login -#[derive(DeriveWhere)] -#[derive_where(Clone, Zeroize(drop))] +#[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( Debug, Eq, Hash, PartialEq; - voprf::NonVerifiableClient, - >::KE1State, + voprf::NonVerifiableClient, + , CS::KeGroup>>::KE1State, CredentialRequest, )] pub struct ClientLogin where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - oprf_client: voprf::NonVerifiableClient, - ke1_state: >::KE1State, - credential_request: CredentialRequest, + pub(crate) oprf_client: voprf::NonVerifiableClient, + pub(crate) ke1_state: , CS::KeGroup>>::KE1State, + pub(crate) credential_request: CredentialRequest, } impl_serialize_and_deserialize_for!( ClientLogin where // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State - ::ScalarLen: Add>, - Sum<::ScalarLen, CredentialRequestLen>: + as Group>::ScalarLen: Add>, + Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength | Add>, ClientLoginLen: ArrayLength, ); /// The state elements the server holds to record a login -#[derive(DeriveWhere)] -#[derive_where(Clone, Zeroize(drop))] +#[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( Debug, Eq, Hash, PartialEq; - >::KE2State, + , CS::KeGroup>>::KE2State, )] pub struct ServerLogin where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - ke2_state: >::KE2State, - #[derive_where(skip(Zeroize))] - _cs: PhantomData, + ke2_state: , CS::KeGroup>>::KE2State, } impl_serialize_and_deserialize_for!(ServerLogin); @@ -195,9 +205,12 @@ impl_serialize_and_deserialize_for!(ServerLogin); impl ServerSetup> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Generate a new instance of server setup pub fn new(rng: &mut R) -> Self { @@ -208,13 +221,16 @@ where /// Length of [`ServerSetup`] in bytes for serialization. pub type ServerSetupLen> = - Sum, S::Len>, ::SkLen>; + Sum>, S::Len>, ::SkLen>; impl> ServerSetup where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Create [`ServerSetup`] with the given keypair pub fn new_with_key( @@ -235,19 +251,20 @@ where pub fn serialize(&self) -> GenericArray> where // ServerSetup: Hash + KeSk + KeSk - OutputSize: Add, - Sum, S::Len>: ArrayLength + Add<::SkLen>, + OutputSize>: Add, + Sum>, S::Len>: + ArrayLength + Add<::SkLen>, ServerSetupLen: ArrayLength, { self.oprf_seed .clone() .concat(self.keypair.private().serialize()) - .concat(self.fake_keypair.private().to_arr()) + .concat(self.fake_keypair.private().serialize()) } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result> { - let seed_len = OutputSize::::USIZE; + let seed_len = OutputSize::>::USIZE; let key_len = ::SkLen::USIZE; let checked_slice = check_slice_size(input, seed_len + key_len + key_len, "server_setup")?; @@ -269,19 +286,22 @@ where // ============ pub(crate) type ClientRegistrationLen = - Sum<::ScalarLen, ::ElemLen>; + Sum< as Group>::ScalarLen, as Group>::ElemLen>; impl ClientRegistration where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // ClientRegistration: KgSk + KgPk - ::ScalarLen: Add<::ElemLen>, + as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, { self.oprf_client @@ -291,8 +311,8 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let client_len = ::ScalarLen::USIZE; - let element_len = ::ElemLen::USIZE; + let client_len = as Group>::ScalarLen::USIZE; + let element_len = as Group>::ElemLen::USIZE; let checked_slice = check_slice_size(input, client_len + element_len, "client_registration")?; @@ -359,7 +379,7 @@ where params.slow_hash, )?; - let mut masking_key = Output::::default(); + let mut masking_key = Output::>::default(); randomized_pwd_hasher .expand(STR_MASKING_KEY, &mut masking_key) .map_err(|_| InternalError::HkdfError)?; @@ -394,19 +414,22 @@ pub type ServerRegistrationLen = RegistrationUploadLen; impl ServerRegistration where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload @@ -426,17 +449,15 @@ where message: RegistrationRequest, credential_identifier: &[u8], ) -> Result, ProtocolError> { - let oprf_key = oprf_key_from_seed::( - &server_setup.oprf_seed, - credential_identifier, - )?; + let oprf_key = + oprf_key_from_seed::(&server_setup.oprf_seed, credential_identifier)?; let server = voprf::NonVerifiableServer::new_with_key(&oprf_key)?; - let evaluate_result = server.evaluate(&message.blinded_element, None)?; + let evaluation_element = server.evaluate(&message.blinded_element, None)?; Ok(ServerRegistrationStartResult { message: RegistrationResponse { - evaluation_element: evaluate_result.message, + evaluation_element, server_s_pk: server_setup.keypair.public().clone(), }, #[cfg(test)] @@ -463,23 +484,26 @@ where // ===== pub(crate) type ClientLoginLen = - Sum::ScalarLen, CredentialRequestLen>, Ke1StateLen>; + Sum as Group>::ScalarLen, CredentialRequestLen>, Ke1StateLen>; impl ClientLogin where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> where // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State - ::ScalarLen: Add>, - Sum<::ScalarLen, CredentialRequestLen>: + as Group>::ScalarLen: Add>, + Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, { @@ -491,14 +515,14 @@ where /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { - let client_len = ::ScalarLen::USIZE; - let request_len = ::ElemLen::USIZE + Ke1MessageLen::::USIZE; + let client_len = as Group>::ScalarLen::USIZE; + let request_len = as Group>::ElemLen::USIZE + Ke1MessageLen::::USIZE; let state_len = Ke1StateLen::::USIZE; let checked_slice = check_slice_size(input, client_len + request_len + state_len, "client_login")?; let ke1_state = - >::KE1State::from_bytes( + , CS::KeGroup>>::KE1State::from_bytes( &checked_slice[client_len + request_len..], )?; Ok(Self { @@ -509,29 +533,16 @@ where ke1_state, }) } - - /// Only used for testing zeroize - #[cfg(test)] - pub(crate) fn to_vec(&self) -> std::vec::Vec - where - // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, - CredentialRequestLen: ArrayLength, - { - [ - self.oprf_client.serialize().to_vec(), - self.credential_request.serialize().to_vec(), - self.ke1_state.to_bytes().to_vec(), - ] - .concat() - } } impl ClientLogin where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Returns an initial "blinded" password request to send to the server, as /// well as a ClientLogin @@ -567,8 +578,9 @@ where ) -> Result, ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { // Check if beta value from server is equal to alpha value from client @@ -589,7 +601,7 @@ where params.slow_hash, )?; - let mut masking_key = Output::::default(); + let mut masking_key = Output::>::default(); randomized_pwd_hasher .expand(STR_MASKING_KEY, &mut masking_key) .map_err(|_| InternalError::HkdfError)?; @@ -617,14 +629,15 @@ where err => err, })?; - let beta = credential_response.evaluation_element.value().to_arr(); + let beta = OprfGroup::::serialize_elem(credential_response.evaluation_element.value()); let credential_response_component = CredentialResponse::::serialize_without_ke( &beta, &credential_response.masking_nonce, &credential_response.masked_response, ); - let blinded_element = self.credential_request.blinded_element.value().to_arr(); + let blinded_element = + OprfGroup::::serialize_elem(self.credential_request.blinded_element.value()); let ke1_message = self.credential_request.ke1_message.to_bytes(); let serialized_credential_request = CredentialRequest::::serialize_iter(&blinded_element, &ke1_message); @@ -660,9 +673,12 @@ where impl ServerLogin where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Serialization into bytes pub fn serialize(&self) -> GenericArray> { @@ -672,9 +688,8 @@ where /// Deserialization from bytes pub fn deserialize(bytes: &[u8]) -> Result { Ok(Self { - _cs: PhantomData, ke2_state: - >::KE2State::from_bytes( + , CS::KeGroup>>::KE2State::from_bytes( bytes, )?, }) @@ -695,8 +710,9 @@ where ) -> Result, ProtocolError> where // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let record = match password_file { @@ -728,29 +744,27 @@ where let (id_u, id_s) = bytestrings_from_identifiers::( identifiers, - client_s_pk.to_arr(), - server_s_pk.to_arr(), + client_s_pk.to_bytes(), + server_s_pk.to_bytes(), ) .map_err(ProtocolError::into_custom)?; - let blinded_element = credential_request.blinded_element.value().to_arr(); + let blinded_element = + OprfGroup::::serialize_elem(credential_request.blinded_element.value()); let ke1_message = credential_request.ke1_message.to_bytes(); let credential_request_bytes = CredentialRequest::::serialize_iter(&blinded_element, &ke1_message); - let oprf_key = oprf_key_from_seed::( - &server_setup.oprf_seed, - credential_identifier, - ) - .map_err(ProtocolError::into_custom)?; + let oprf_key = + oprf_key_from_seed::(&server_setup.oprf_seed, credential_identifier) + .map_err(ProtocolError::into_custom)?; let server = voprf::NonVerifiableServer::new_with_key(&oprf_key) .map_err(|e| ProtocolError::into_custom(e.into()))?; - let evaluate_result = server + let evaluation_element = server .evaluate(&credential_request.blinded_element, None) .map_err(|e| ProtocolError::into_custom(e.into()))?; - let evaluation_element = evaluate_result.message; - let beta = evaluation_element.value().to_arr(); + let beta = OprfGroup::::serialize_elem(evaluation_element.value()); let credential_response_component = CredentialResponse::::serialize_without_ke(&beta, &masking_nonce, &masked_response); @@ -758,7 +772,7 @@ where rng, credential_request_bytes, credential_response_component, - credential_request.ke1_message, + credential_request.ke1_message.clone(), client_s_pk, server_s_sk.clone(), id_u.iter(), @@ -776,7 +790,6 @@ where Ok(ServerLoginStartResult { message: credential_response, state: Self { - _cs: PhantomData, ke2_state: result.0, }, #[cfg(test)] @@ -794,14 +807,13 @@ where self, message: CredentialFinalization, ) -> Result, ProtocolError> { - let session_key = >::finish_ke( + let session_key = , CS::KeGroup>>::finish_ke( message.ke3_message, &self.ke2_state, )?; Ok(ServerLoginFinishResult { session_key, - _cs: PhantomData, #[cfg(test)] state: self, }) @@ -823,13 +835,15 @@ pub struct Identifiers<'a> { } /// Optional parameters for client registration finish -#[derive(DeriveWhere)] #[derive_where(Clone, Default)] pub struct ClientRegistrationFinishParameters<'i, 'h, CS: CipherSuite> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Specifying the identifiers idU and idS pub identifiers: Identifiers<'i>, @@ -839,9 +853,12 @@ where impl<'i, 'h, CS: CipherSuite> ClientRegistrationFinishParameters<'i, 'h, CS> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Create a new [`ClientRegistrationFinishParameters`] pub fn new(identifiers: Identifiers<'i>, slow_hash: Option<&'h CS::SlowHash>) -> Self { @@ -853,13 +870,15 @@ where } /// Contains the fields that are returned by a client registration start -#[derive(DeriveWhere)] #[derive_where(Clone)] pub struct ClientRegistrationStartResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The registration request message to be sent to the server pub message: RegistrationRequest, @@ -869,18 +888,20 @@ where } /// Contains the fields that are returned by a client registration finish -#[derive(DeriveWhere)] #[derive_where(Clone)] pub struct ClientRegistrationFinishResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The registration upload message to be sent to the server pub message: RegistrationUpload, /// The export key output by client registration - pub export_key: Output, + pub export_key: Output>, /// The server's static public key pub server_s_pk: PublicKey, /// Instance of the ClientRegistration, only used in tests for checking @@ -889,37 +910,41 @@ where pub state: ClientRegistration, /// AuthKey, only used in tests #[cfg(test)] - pub auth_key: Output, + pub auth_key: Output>, /// Password derived key, only used in tests #[cfg(test)] - pub randomized_pwd: Output, + pub randomized_pwd: Output>, } /// Contains the fields that are returned by a server registration start. Note /// that there is no state output in this step -#[derive(DeriveWhere)] #[derive_where(Clone)] pub struct ServerRegistrationStartResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The registration resposne message to send to the client pub message: RegistrationResponse, /// OPRF key, only used in tests #[cfg(test)] - pub oprf_key: GenericArray::ScalarLen>, + pub oprf_key: GenericArray as Group>::ScalarLen>, } /// Contains the fields that are returned by a client login start -#[derive(DeriveWhere)] #[derive_where(Clone)] pub struct ClientLoginStartResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The message to send to the server to begin the login protocol pub message: CredentialRequest, @@ -928,13 +953,15 @@ where } /// Optional parameters for client login finish -#[derive(DeriveWhere)] #[derive_where(Clone, Default)] pub struct ClientLoginFinishParameters<'c, 'i, 'h, CS: CipherSuite> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Specifying a context field that the server must agree on pub context: Option<&'c [u8]>, @@ -947,9 +974,12 @@ where impl<'c, 'i, 'h, CS: CipherSuite> ClientLoginFinishParameters<'c, 'i, 'h, CS> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Create a new [`ClientLoginFinishParameters`] pub fn new( @@ -966,20 +996,22 @@ where } /// Contains the fields that are returned by a client login finish -#[derive(DeriveWhere)] #[derive_where(Clone)] pub struct ClientLoginFinishResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The message to send to the server to complete the protocol pub message: CredentialFinalization, /// The session key - pub session_key: Output, + pub session_key: Output>, /// The client-side export key - pub export_key: Output, + pub export_key: Output>, /// The server's static public key pub server_s_pk: PublicKey, /// Instance of the ClientLogin, only used in tests for checking zeroize @@ -987,26 +1019,27 @@ where pub state: ClientLogin, /// Handshake secret, only used in tests #[cfg(test)] - pub handshake_secret: Output, + pub handshake_secret: Output>, /// Client MAC key, only used in tests #[cfg(test)] - pub client_mac_key: Output, + pub client_mac_key: Output>, } /// Contains the fields that are returned by a server login finish -#[derive(DeriveWhere)] #[derive_where(Clone)] #[cfg_attr(not(test), derive_where(Debug))] #[cfg_attr(test, derive_where(Debug; ServerLogin))] pub struct ServerLoginFinishResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The session key between client and server - pub session_key: Output, - _cs: PhantomData, + pub session_key: Output>, /// Instance of the ClientRegistration, only used in tests for checking /// zeroize #[cfg(test)] @@ -1024,19 +1057,21 @@ pub struct ServerLoginStartParameters<'c, 'i> { } /// Contains the fields that are returned by a server login start -#[derive(DeriveWhere)] #[derive_where(Clone)] #[derive_where( Debug; - CS::OprfGroup, - >::KE2Message, - >::KE2State, + voprf::EvaluationElement, + , CS::KeGroup>>::KE2Message, + , CS::KeGroup>>::KE2State, )] pub struct ServerLoginStartResult where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// The message to send back to the client pub message: CredentialResponse, @@ -1044,13 +1079,13 @@ where pub state: ServerLogin, /// Handshake secret, only used in tests #[cfg(test)] - pub handshake_secret: Output, + pub handshake_secret: Output>, /// Server MAC key, only used in tests #[cfg(test)] - pub server_mac_key: Output, + pub server_mac_key: Output>, /// OPRF key, only used in tests #[cfg(test)] - pub oprf_key: GenericArray::ScalarLen>, + pub oprf_key: GenericArray as Group>::ScalarLen>, } //////////////////////////////////////////////// @@ -1062,14 +1097,17 @@ where #[allow(clippy::type_complexity)] fn get_password_derived_key( input: &[u8], - oprf_client: voprf::NonVerifiableClient, - evaluation_element: voprf::EvaluationElement, + oprf_client: voprf::NonVerifiableClient, + evaluation_element: voprf::EvaluationElement, slow_hash: Option<&CS::SlowHash>, -) -> Result<(Output, Hkdf), ProtocolError> +) -> Result<(Output>, Hkdf>), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let oprf_output = oprf_client.finalize(input, &evaluation_element, None)?; @@ -1080,63 +1118,74 @@ where } .map_err(ProtocolError::from)?; - let mut hkdf = HkdfExtract::::new(None); + let mut hkdf = HkdfExtract::>::new(None); hkdf.input_ikm(&oprf_output); hkdf.input_ikm(&hardened_output); Ok(hkdf.finalize()) } -fn oprf_key_from_seed( - oprf_seed: &Output, +fn oprf_key_from_seed( + oprf_seed: &Output, credential_identifier: &[u8], -) -> Result, ProtocolError> +) -> Result::ScalarLen>, ProtocolError> where - D::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + ::OutputSize: + IsLess + IsLessOrEqual<::BlockSize>, + CS::Hash: Hash, + ::Core: ProxyHash, + <::Core as BlockSizeUser>::BlockSize: IsLess, + Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { - let mut ikm = GenericArray::<_, G::ScalarLen>::default(); - Hkdf::::from_prk(oprf_seed) + let mut ikm = GenericArray::<_, ::ScalarLen>::default(); + Hkdf::::from_prk(oprf_seed) .ok() .and_then(|hkdf| { hkdf.expand_multi_info(&[credential_identifier, STR_OPRF_KEY], &mut ikm) .ok() }) .ok_or(InternalError::HkdfError)?; - Ok(G::scalar_as_bytes(G::hash_to_scalar::( - [ikm.as_slice()], - GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR), - )?)) + Ok(CS::Group::serialize_scalar( + CS::Group::hash_to_scalar::( + &[ikm.as_slice()], + &GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR), + )?, + )) } -#[derive(DeriveWhere)] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, PartialEq)] pub(crate) struct MaskedResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { pub(crate) nonce: GenericArray, - pub(crate) hash: Output, + pub(crate) hash: Output>, pub(crate) pk: GenericArray::PkLen>, } pub(crate) type MaskedResponseLen = - Sum>, ::PkLen>; + Sum>>, ::PkLen>; impl MaskedResponse where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { pub(crate) fn serialize(&self) -> GenericArray> where // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { self.nonce.concat(self.hash.clone()).concat(self.pk.clone()) @@ -1144,7 +1193,7 @@ where pub(crate) fn deserialize(bytes: &[u8]) -> Self { let nonce = NonceLen::USIZE; - let hash = nonce + OutputSize::::USIZE; + let hash = nonce + OutputSize::>::USIZE; let pk = hash + ::PkLen::USIZE; Self { @@ -1166,25 +1215,27 @@ fn mask_response( envelope: &Envelope, ) -> Result, ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, - + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut xor_pad = GenericArray::<_, MaskedResponseLen>::default(); - Hkdf::::from_prk(masking_key) + Hkdf::>::from_prk(masking_key) .map_err(|_| InternalError::HkdfError)? .expand_multi_info(&[masking_nonce, STR_CREDENTIAL_RESPONSE_PAD], &mut xor_pad) .map_err(|_| InternalError::HkdfError)?; for (x1, x2) in xor_pad.iter_mut().zip( server_s_pk - .to_arr() + .to_bytes() .as_slice() .iter() .chain(envelope.serialize().iter()), @@ -1201,17 +1252,20 @@ fn unmask_response( masked_response: &MaskedResponse, ) -> Result<(PublicKey, Envelope), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut xor_pad = GenericArray::<_, MaskedResponseLen>::default(); - Hkdf::::from_prk(masking_key) + Hkdf::>::from_prk(masking_key) .map_err(|_| InternalError::HkdfError)? .expand_multi_info(&[masking_nonce, STR_CREDENTIAL_RESPONSE_PAD], &mut xor_pad) .map_err(|_| InternalError::HkdfError)?; @@ -1221,12 +1275,9 @@ where } let key_len = ::PkLen::USIZE; - let unchecked_server_s_pk = PublicKey::from_bytes(&xor_pad[..key_len])?; - let envelope = Envelope::deserialize(&xor_pad[key_len..])?; - - // Ensure that public key is valid - let server_s_pk = KeyPair::::check_public_key(unchecked_server_s_pk) + let server_s_pk = PublicKey::deserialize(&xor_pad[..key_len]) .map_err(|_| ProtocolError::SerializationError)?; + let envelope = Envelope::deserialize(&xor_pad[key_len..])?; Ok((server_s_pk, envelope)) } @@ -1257,27 +1308,25 @@ pub(crate) fn bytestrings_from_identifiers( fn blind( rng: &mut R, password: &[u8], -) -> Result, voprf::Error> +) -> Result, voprf::Error> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { #[cfg(not(test))] let result = voprf::NonVerifiableClient::blind(password, rng)?; #[cfg(test)] let result = { - let mut blind_bytes = GenericArray::default(); + let mut blind_bytes = GenericArray::<_, as Group>::ScalarLen>::default(); let blind = loop { rng.fill_bytes(&mut blind_bytes); - let scalar = ::from_scalar_slice_unchecked(&blind_bytes)?; - match scalar - .ct_eq(&::scalar_zero()) - .into() - { - false => break scalar, - true => (), + if let Ok(scalar) = as Group>::deserialize_scalar(&blind_bytes) { + break scalar; } }; voprf::NonVerifiableClient::deterministic_blind_unchecked(password, blind)? diff --git a/src/serialization/mod.rs b/src/serialization/mod.rs index 10f31fd5..81060f90 100644 --- a/src/serialization/mod.rs +++ b/src/serialization/mod.rs @@ -12,7 +12,7 @@ use generic_array::typenum::{U0, U2}; use generic_array::{ArrayLength, GenericArray}; use hmac::Mac; -use crate::errors::ProtocolError; +use crate::errors::{InternalError, ProtocolError}; // Corresponds to the I2OSP() function from RFC8017 pub(crate) fn i2osp>( @@ -157,6 +157,20 @@ impl MacExt for T { } } +pub(crate) trait GenericArrayExt { + fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError>; +} + +impl> GenericArrayExt for GenericArray { + fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError> { + if slice.len() == L::USIZE { + Ok(Self::from_slice(slice)) + } else { + Err(InternalError::InvalidByteSequence) + } + } +} + #[cfg(test)] mod tests; diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs old mode 100755 new mode 100644 index 2a2e3e9c..4d68dbd4 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -10,8 +10,8 @@ use std::vec; use std::vec::Vec; use digest::core_api::{BlockSizeUser, CoreProxy}; -use digest::Output; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U256}; +use digest::{Output, OutputSizeUser}; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U256}; use generic_array::ArrayLength; use proptest::collection::vec; use proptest::prelude::*; @@ -19,16 +19,16 @@ use rand::rngs::OsRng; use rand::RngCore; use voprf::Group; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::{Envelope, EnvelopeLen, InnerEnvelopeMode}; use crate::errors::*; -use crate::hash::{OutputSize, ProxyHash}; +use crate::hash::{Hash, OutputSize, ProxyHash}; use crate::key_exchange::group::KeGroup; use crate::key_exchange::traits::{ FromBytes, Ke1MessageLen, Ke1StateLen, Ke2MessageLen, KeyExchange, ToBytes, }; use crate::key_exchange::tripledh::{NonceLen, TripleDH}; -use crate::keypair::KeyPair; +use crate::keypair::{KeyPair, SecretKey}; use crate::messages::CredentialResponseWithoutKeLen; use crate::opaque::{ClientLoginLen, ClientRegistrationLen, MaskedResponseLen}; use crate::serialization::{i2osp, os2ip}; @@ -36,31 +36,32 @@ use crate::*; #[cfg(feature = "ristretto255")] struct Ristretto255; + #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255 { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = crate::Ristretto255; + type KeGroup = crate::Ristretto255; type KeyExchange = TripleDH; - type Hash = sha2::Sha512; type SlowHash = crate::slow_hash::NoOpHash; } -#[cfg(feature = "p256")] struct P256; -#[cfg(feature = "p256")] + impl CipherSuite for P256 { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; + type OprfGroup = ::p256::NistP256; + type KeGroup = ::p256::NistP256; type KeyExchange = TripleDH; - type Hash = sha2::Sha256; type SlowHash = crate::slow_hash::NoOpHash; } -fn random_point() -> CS::KeGroup +fn random_point() -> ::Pk where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut rng = OsRng; let sk = CS::KeGroup::random_sk(&mut rng); @@ -71,18 +72,20 @@ where fn client_registration_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // ClientRegistration: KgSk + KgPk - ::ScalarLen: Add<::ElemLen>, + as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, { let pw = b"hunter2"; let mut rng = OsRng; - let blind_result = - &voprf::NonVerifiableClient::::blind(pw, &mut rng)?; + let blind_result = &voprf::NonVerifiableClient::::blind(pw, &mut rng)?; let bytes: Vec = blind_result .state @@ -100,7 +103,6 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -110,22 +112,25 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> { fn server_registration_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { // If we don't have envelope and client_pk, the server registration just let mut rng = OsRng; - let mut masking_key = Output::::default(); + let mut masking_key = Output::>::default(); rng.fill_bytes(&mut masking_key); // Construct a mock envelope @@ -135,12 +140,12 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> { // ciphertext which is an encrypted private key //mock_envelope_bytes.extend_from_slice(&ciphertext); // length-MAC_SIZE hmac - mock_envelope_bytes.extend_from_slice(&Output::::default()); + mock_envelope_bytes.extend_from_slice(&Output::>::default()); let mock_client_kp = KeyPair::::generate_random(&mut rng); // serialization order: oprf_key, public key, envelope let mut bytes = Vec::::new(); - bytes.extend_from_slice(&mock_client_kp.public().to_arr()); + bytes.extend_from_slice(&mock_client_kp.public().to_bytes()); bytes.extend_from_slice(&masking_key); bytes.extend_from_slice(&mock_envelope_bytes); let reg = ServerRegistration::::deserialize(&bytes)?; @@ -151,7 +156,6 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -161,12 +165,15 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> { fn registration_request_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let pt = random_point::(); - let pt_bytes = pt.to_arr().to_vec(); + let pt_bytes = CS::KeGroup::serialize_pk(&pt); let mut input = Vec::new(); input.extend_from_slice(&pt_bytes); @@ -176,13 +183,13 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> { assert_eq!(input, *r1_bytes); // Assert that identity group element is rejected - let identity = CS::OprfGroup::identity(); - let identity_bytes = identity.to_arr().to_vec(); + let identity = OprfGroup::::identity_elem(); + let identity_bytes = OprfGroup::::serialize_elem(identity).to_vec(); assert!(matches!( RegistrationRequest::::deserialize(&identity_bytes), Err(ProtocolError::LibraryError(InternalError::OprfError( - voprf::Error::PointError, + voprf::Error::Deserialization, ))) )); @@ -191,7 +198,6 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -201,18 +207,21 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> { fn registration_response_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, { let pt = random_point::(); - let beta_bytes = pt.to_arr(); + let beta_bytes = CS::KeGroup::serialize_pk(&pt); let mut rng = OsRng; let skp = KeyPair::::generate_random(&mut rng); - let pubkey_bytes = skp.public().to_arr(); + let pubkey_bytes = skp.public().to_bytes(); let mut input = Vec::new(); input.extend_from_slice(&beta_bytes); @@ -223,15 +232,15 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> { assert_eq!(input, *r2_bytes); // Assert that identity group element is rejected - let identity = CS::OprfGroup::identity(); - let identity_bytes = identity.to_arr().to_vec(); + let identity = OprfGroup::::identity_elem(); + let identity_bytes = OprfGroup::::serialize_elem(identity).to_vec(); assert!(matches!( RegistrationResponse::::deserialize( &[identity_bytes, pubkey_bytes.to_vec()].concat() ), Err(ProtocolError::LibraryError(InternalError::OprfError( - voprf::Error::PointError, + voprf::Error::Deserialization, ))) )); @@ -240,7 +249,6 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -250,28 +258,31 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> { fn registration_upload_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { let mut rng = OsRng; let skp = KeyPair::::generate_random(&mut rng); - let pubkey_bytes = skp.public().to_arr(); + let pubkey_bytes = skp.public().to_bytes(); let mut key = [0u8; 32]; rng.fill_bytes(&mut key); let mut nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut nonce); - let mut masking_key = Output::::default(); + let mut masking_key = Output::>::default(); rng.fill_bytes(&mut masking_key); let randomized_pwd_hasher = hkdf::Hkdf::new(None, &key); @@ -299,7 +310,6 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -309,22 +319,29 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> { fn credential_request_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, { let mut rng = OsRng; let alpha = random_point::(); - let alpha_bytes = alpha.to_arr(); + let alpha_bytes = CS::KeGroup::serialize_pk(&alpha); let client_e_kp = KeyPair::::generate_random(&mut rng); let mut client_nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut client_nonce); - let ke1m: Vec = [client_nonce.as_ref(), client_e_kp.public()].concat(); + let ke1m: Vec = [ + client_nonce.as_ref(), + client_e_kp.public().to_bytes().as_ref(), + ] + .concat(); let mut input = Vec::new(); input.extend_from_slice(&alpha_bytes); @@ -335,13 +352,13 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> { assert_eq!(input, *l1_bytes); // Assert that identity group element is rejected - let identity = CS::OprfGroup::identity(); - let identity_bytes = identity.to_arr().to_vec(); + let identity = OprfGroup::::identity_elem(); + let identity_bytes = OprfGroup::::serialize_elem(identity).to_vec(); assert!(matches!( CredentialRequest::::deserialize(&[identity_bytes, ke1m.to_vec()].concat()), Err(ProtocolError::LibraryError(InternalError::OprfError( - voprf::Error::PointError, + voprf::Error::Deserialization, ))) )); @@ -350,7 +367,6 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -360,24 +376,28 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> { fn credential_response_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, CredentialResponseLen: ArrayLength, { let pt = random_point::(); - let pt_bytes = pt.to_arr(); + let pt_bytes = CS::KeGroup::serialize_pk(&pt); let mut rng = OsRng; @@ -385,16 +405,21 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { rng.fill_bytes(&mut masking_nonce); let mut masked_response = - vec![0u8; ::ElemLen::USIZE + Envelope::::len()]; + vec![0u8; as Group>::ElemLen::USIZE + Envelope::::len()]; rng.fill_bytes(&mut masked_response); let server_e_kp = KeyPair::::generate_random(&mut rng); - let mut mac = Output::::default(); + let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); let mut server_nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut server_nonce); - let ke2m: Vec = [server_nonce.as_ref(), server_e_kp.public(), &mac].concat(); + let ke2m: Vec = [ + server_nonce.as_ref(), + server_e_kp.public().to_bytes().as_ref(), + &mac, + ] + .concat(); let mut input = Vec::new(); input.extend_from_slice(&pt_bytes); @@ -407,8 +432,8 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { assert_eq!(input, *l2_bytes); // Assert that identity group element is rejected - let identity = CS::OprfGroup::identity(); - let identity_bytes = identity.to_arr().to_vec(); + let identity = OprfGroup::::identity_elem(); + let identity_bytes = OprfGroup::::serialize_elem(identity).to_vec(); assert!(matches!( CredentialResponse::::deserialize( @@ -421,7 +446,7 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { .concat() ), Err(ProtocolError::LibraryError(InternalError::OprfError( - voprf::Error::PointError, + voprf::Error::Deserialization, ))) )); @@ -430,7 +455,6 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -440,12 +464,15 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { fn credential_finalization_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut rng = OsRng; - let mut mac = Output::::default(); + let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); let input = mac; @@ -459,7 +486,6 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -469,15 +495,18 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> { fn client_login_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State - ::ScalarLen: Add>, - Sum<::ScalarLen, CredentialRequestLen>: + as Group>::ScalarLen: Add>, + Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, { @@ -489,19 +518,22 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> { rng.fill_bytes(&mut client_nonce); let l1_data = [ - client_e_kp.private().to_arr().to_vec(), + client_e_kp.private().serialize().to_vec(), client_nonce.to_vec(), ] .concat(); - let blind_result = - voprf::NonVerifiableClient::::blind(pw, &mut rng)?; + let blind_result = voprf::NonVerifiableClient::::blind(pw, &mut rng)?; let credential_request = CredentialRequest:: { blinded_element: blind_result.message, ke1_message: - >::KE1Message::from_bytes( - &[client_nonce.as_ref(), client_e_kp.public()].concat(), + , CS::KeGroup>>::KE1Message::from_bytes( + &[ + client_nonce.as_ref(), + client_e_kp.public().to_bytes().as_ref(), + ] + .concat(), )?, }; @@ -521,7 +553,6 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -531,9 +562,12 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> { fn ke1_message_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut rng = OsRng; @@ -541,9 +575,15 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> { let mut client_nonce = vec![0u8; NonceLen::USIZE]; rng.fill_bytes(&mut client_nonce); - let ke1m = [client_nonce.as_slice(), client_e_kp.public()].concat(); + let ke1m = [ + client_nonce.as_slice(), + client_e_kp.public().to_bytes().as_ref(), + ] + .concat(); let reg = - >::KE1Message::from_bytes(&ke1m)?; + , CS::KeGroup>>::KE1Message::from_bytes( + &ke1m, + )?; let reg_bytes = reg.to_bytes(); assert_eq!(*reg_bytes, ke1m); @@ -552,7 +592,6 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -562,22 +601,32 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> { fn ke2_message_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut rng = OsRng; let server_e_kp = KeyPair::::generate_random(&mut rng); - let mut mac = Output::::default(); + let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); let mut server_nonce = vec![0u8; NonceLen::USIZE]; rng.fill_bytes(&mut server_nonce); - let ke2m: Vec = [server_nonce.as_slice(), server_e_kp.public(), &mac].concat(); + let ke2m: Vec = [ + server_nonce.as_slice(), + server_e_kp.public().to_bytes().as_ref(), + &mac, + ] + .concat(); let reg = - >::KE2Message::from_bytes(&ke2m)?; + , CS::KeGroup>>::KE2Message::from_bytes( + &ke2m, + )?; let reg_bytes = reg.to_bytes(); assert_eq!(*reg_bytes, ke2m); @@ -586,7 +635,6 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -596,18 +644,23 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> { fn ke3_message_roundtrip() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut rng = OsRng; - let mut mac = Output::::default(); + let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); let ke3m: Vec = [mac].concat(); let reg = - >::KE3Message::from_bytes(&ke3m)?; + , CS::KeGroup>>::KE3Message::from_bytes( + &ke3m, + )?; let reg_bytes = reg.to_bytes(); assert_eq!(*reg_bytes, ke3m); @@ -616,7 +669,6 @@ fn ke3_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; Ok(()) @@ -707,5 +759,4 @@ macro_rules! test { #[cfg(feature = "ristretto255")] test!(ristretto255, Ristretto255); -#[cfg(feature = "p256")] test!(p256, P256); diff --git a/src/slow_hash.rs b/src/slow_hash.rs index 522d923c..7ee63a21 100644 --- a/src/slow_hash.rs +++ b/src/slow_hash.rs @@ -7,48 +7,39 @@ //! Trait specifying a slow hashing function -use digest::core_api::BlockSizeUser; -use digest::Output; -use generic_array::typenum::{IsLess, Le, NonZero, U256}; +use generic_array::{ArrayLength, GenericArray}; use crate::errors::InternalError; -use crate::hash::{Hash, ProxyHash}; /// Used for the slow hashing function in OPAQUE -pub trait SlowHash: Default -where - D::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, -{ +pub trait SlowHash: Default { /// Computes the slow hashing function - fn hash(&self, input: Output) -> Result, InternalError>; + fn hash>( + &self, + input: GenericArray, + ) -> Result, InternalError>; } /// A no-op hash which simply returns its input #[derive(Default)] pub struct NoOpHash; -impl SlowHash for NoOpHash -where - D::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, -{ - fn hash(&self, input: Output) -> Result, InternalError> { +impl SlowHash for NoOpHash { + fn hash>( + &self, + input: GenericArray, + ) -> Result, InternalError> { Ok(input) } } #[cfg(feature = "slow-hash")] -impl SlowHash for argon2::Argon2<'_> -where - D::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, -{ - fn hash(&self, input: Output) -> Result, InternalError> { - let mut output = Output::::default(); +impl SlowHash for argon2::Argon2<'_> { + fn hash>( + &self, + input: GenericArray, + ) -> Result, InternalError> { + let mut output = GenericArray::default(); self.hash_password_into(&input, &[0; argon2::MIN_SALT_LEN], &mut output) .map_err(|_| InternalError::SlowHashError)?; Ok(output) diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs old mode 100755 new mode 100644 index 5644f679..fe3a00b4 --- a/src/tests/full_test.rs +++ b/src/tests/full_test.rs @@ -8,27 +8,27 @@ #![allow(unsafe_code)] use core::ops::Add; -use std::string::{String, ToString}; +use std::string::String; use std::vec::Vec; -use std::{format, println, vec}; +use std::{format, println, ptr, vec}; use digest::core_api::{BlockSizeUser, CoreProxy}; -use digest::Output; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, Unsigned, U256}; +use digest::{Output, OutputSizeUser}; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, Unsigned, U256}; use generic_array::ArrayLength; use rand::rngs::OsRng; use serde_json::Value; use subtle::ConstantTimeEq; use voprf::Group; -use zeroize::Zeroize; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::EnvelopeLen; use crate::errors::*; -use crate::hash::{OutputSize, ProxyHash}; +use crate::hash::{Hash, OutputSize, ProxyHash}; use crate::key_exchange::group::KeGroup; use crate::key_exchange::traits::{Ke1MessageLen, Ke1StateLen, Ke2MessageLen}; use crate::key_exchange::tripledh::{NonceLen, TripleDH}; +use crate::keypair::SecretKey; use crate::messages::{ CredentialRequestLen, CredentialResponseLen, CredentialResponseWithoutKeLen, RegistrationResponseLen, RegistrationUploadLen, @@ -43,45 +43,43 @@ use crate::*; #[cfg(feature = "ristretto255")] struct Ristretto255; + #[cfg(feature = "ristretto255")] impl CipherSuite for Ristretto255 { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; + type OprfGroup = crate::Ristretto255; + type KeGroup = crate::Ristretto255; type KeyExchange = TripleDH; - type Hash = sha2::Sha512; type SlowHash = NoOpHash; } -#[cfg(feature = "p256")] struct P256; -#[cfg(feature = "p256")] + impl CipherSuite for P256 { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; + type OprfGroup = p256::NistP256; + type KeGroup = p256::NistP256; type KeyExchange = TripleDH; - type Hash = sha2::Sha256; type SlowHash = NoOpHash; } #[cfg(all(feature = "x25519", feature = "ristretto255"))] struct X25519Ristretto255; + #[cfg(all(feature = "x25519", feature = "ristretto255"))] impl CipherSuite for X25519Ristretto255 { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = x25519_dalek::PublicKey; + type OprfGroup = crate::Ristretto255; + type KeGroup = crate::X25519; type KeyExchange = TripleDH; - type Hash = sha2::Sha512; type SlowHash = NoOpHash; } -#[cfg(all(feature = "x25519", feature = "p256"))] +#[cfg(feature = "x25519")] struct X25519P256; -#[cfg(all(feature = "x25519", feature = "p256"))] + +#[cfg(feature = "x25519")] impl CipherSuite for X25519P256 { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = x25519_dalek::PublicKey; + type OprfGroup = p256::NistP256; + type KeGroup = crate::X25519; type KeyExchange = TripleDH; - type Hash = sha2::Sha256; type SlowHash = NoOpHash; } @@ -162,7 +160,6 @@ static TEST_VECTOR_RISTRETTO255: &str = r#" } "#; -#[cfg(feature = "p256")] static TEST_VECTOR_P256: &str = r#" { "client_s_pk": "02ec5dd688a3aa66022860d4bfed2dcb01a5da07a0b4ff0c84d9f8749bd478c293", @@ -203,83 +200,81 @@ static TEST_VECTOR_P256: &str = r#" #[cfg(all(feature = "x25519", feature = "ristretto255"))] static TEST_VECTOR_X25519_RISTRETTO255: &str = r#" { - "client_s_pk": "d6ea34b61fa4625c1197f8f9fd51bc7023d4dfb0e17a95cf0ec38488ffff072c", - "client_s_sk": "f8fe7d4c525bd238c501c78a7b6ab26e076bb22c6b409ca08e34875ee4055850", - "client_e_pk": "7b0d1002539befa86f0cdf2a281f538842ec685bad21e9057a92390846ca0047", - "client_e_sk": "30e51bf7c5734fd3d1465b20affb65dc342f06513df999822832aa464aa29c5a", - "server_s_pk": "b6791c7cad7775b6cbc0bfa580319a1de159981771c59b0b86afeeff2767365a", - "server_s_sk": "68bfdb4e00e93059fb35e90db641ae1ef7af0fc8a7e013e2990431cf4c708563", - "server_e_pk": "c68d13eacc23578e731d78d2ccc37e2ff8e7cfdac3f76ee54d9ae40dd1167325", - "server_e_sk": "68b6d213f11d303e61929d299ca2424947e136d5a56b1400dda6286eaf5e4278", - "fake_sk": "c8f71d7e7864a25ee4e786744c5059ca268b7cf7a7610b4b3d763f368fae6972", + "client_s_pk": "4df1ab49521829e233f34b412d48598d046afa20156f117898b7809b070ab526", + "client_s_sk": "9055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a", + "client_e_pk": "9bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d", + "client_e_sk": "388fac72f9c2e9aeeb189963015f7af1692a4a31fefaf06b4ecb66d066d9fe43", + "server_s_pk": "f2f02607a409b5de08ee6e1e51ae674462397997682ea7c48c2d3c762378075b", + "server_s_sk": "c06fed7591d65aa5f6a23cda5d53bde59707bc2d62c2ba61382380b77cae497a", + "server_e_pk": "ee5251c72b241bfa4d926fed7d5082ee31a406e622731550912ac0fce105515f", + "server_e_sk": "b018aa7067155ce9bb6d2fdbc163e706888d8e0cdff1e47f45073556abc8da5a", + "fake_sk": "b8c3c7caec7ef8985a8c84dc183d98e2dbc9c30bd13b86e9c37c810fa0e1cc5e", "credential_identifier": "637265644964656e746966696572", "id_u": "696455", "id_s": "696453", "password": "70617373776f7264", - "blinding_factor": "fa0bbeb200bef1802f3317c0e6b92590d9431fb6f5cb7f579d0865950172e40f", - "oprf_seed": "8bbe6e550d125d9169342b5683b085be3aee7e6414fe2a4f6db2aa3493b16a9b75f109725d6d92c13f3f2814dec17f83e2fd20cf8b922ca1d928e8bf476f8154", - "masking_nonce": "885aa518b13d78757415f8839e1505a4ae8b5f04b6904ce9aff6de6d156d94756f3cb40352bbdafe521da49bf9a57bcde3597114161b023cfbf3b79051d2ee0d", - "envelope_nonce": "e5c5bb34123bb9b08eb961c6f3a94c6b627f1c5bcd3527d46a1652f662e078ac", - "client_nonce": "7fb4b8f81eefe57a8b1cf5d75465d557e04b21ed7800356713ecc63b0ebbfca5", - "server_nonce": "9e3f8ceb7174fdd7ceb2f1e37d4cd483e28e18fa60457416d2d5c468ae7501e7", + "blinding_factor": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0b", + "oprf_seed": "b430182519702493f1991bbf7506c335b5e6e3899e5f1266a7f4c99dd16bf2efab3355a7e75423c2d0e54ee7cc1c16d3fc8975e47946f4bea95a77a06bfeea7c", + "masking_nonce": "ce8202d2438b73cfe23d5f7bccc172ee6a354d690c1770ef07f4f269978bb0dbd6df845d9d9cb969ec8bf41dadef3835ba1d1dd4360b15ba5ad6cb77b9a53879", + "envelope_nonce": "04c9e2914f5874089839e78eb29d342d3c472c0bdb62e1abedf74bbf505fec79", + "client_nonce": "c01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c16", + "server_nonce": "50fe3f0de7db78443da1eadb15d36d6645ea3f94ffcc57b862befda2a9bd10a5", "context": "636f6e74657874", - "registration_request": "8eda5caa002e6574e677636eeba5967ec25505a125ea12d9857c0d8c3beb3551", - "registration_response": "ecf14ba8fb208a8d5b263170ffd84a9d21751810f52e539938ed22e71f66cb02b6791c7cad7775b6cbc0bfa580319a1de159981771c59b0b86afeeff2767365a", - "registration_upload": "020689ce9ffba0f198d9e63e23902ff1600656fdd604aa47c289d5d073cc472354e891e7c4f89058fd270813d320e0cb97a745722eb8038eec062e5aed5e6b40b88148d43e68b7f457c352c3b6523e0bc79795f651487d007574cbaf7dba317ff8fe7d4c525bd238c501c78a7b6ab26e076bb22c6b409ca08e34875ee4055850ea0fcb59720fdb42fcbddbccbaed60a0aec01d72403c63075468e8a03c9efc25206776154291cbce05d7567a82a10d8303f991b8689643c5727b1886c478a9b8", - "credential_request": "8eda5caa002e6574e677636eeba5967ec25505a125ea12d9857c0d8c3beb35517fb4b8f81eefe57a8b1cf5d75465d557e04b21ed7800356713ecc63b0ebbfca57b0d1002539befa86f0cdf2a281f538842ec685bad21e9057a92390846ca0047", - "credential_response": "ecf14ba8fb208a8d5b263170ffd84a9d21751810f52e539938ed22e71f66cb02885aa518b13d78757415f8839e1505a4ae8b5f04b6904ce9aff6de6d156d94756060ede0b8a8d061eaa376b4578fd39ec064f9f36c7a0602894690da72727b427148a2970ce50d06d93ed74dde1143f7d092f19541e8738c509dd5d34f4411d753959bc295083bc96a0b6e1d9a12a369c83fc2a50fab84276f83a2a63e5d5ba6dbb0b23752b7819c238123f0e69cbccc777fa6c35484608f324a3c30b307ad6068b6d213f11d303e61929d299ca2424947e136d5a56b1400dda6286eaf5e4278549bc184dd7a99b0749dfb1acb8ca862b649567d04b056c0530755d453e4c466d5728608562883eea4c922c313455999720cbbf3c6511d3666365132e39c1b6f094d05e73a75e15fb0869661337c3569fcfca75a9373d8fac9ff29c61be49a0d", - "credential_finalization": "6061b34bc847481034908047ded2b7e08450793091f96b9a425e4e4e24e65810596b2556e1ea1ae57e3f6bf234ba33fc393fe4fa98de984760df870a454fcdc9", - "client_registration_state": "fa0bbeb200bef1802f3317c0e6b92590d9431fb6f5cb7f579d0865950172e40f8eda5caa002e6574e677636eeba5967ec25505a125ea12d9857c0d8c3beb3551", - "client_login_state": "fa0bbeb200bef1802f3317c0e6b92590d9431fb6f5cb7f579d0865950172e40f8eda5caa002e6574e677636eeba5967ec25505a125ea12d9857c0d8c3beb35517fb4b8f81eefe57a8b1cf5d75465d557e04b21ed7800356713ecc63b0ebbfca57b0d1002539befa86f0cdf2a281f538842ec685bad21e9057a92390846ca004730e51bf7c5734fd3d1465b20affb65dc342f06513df999822832aa464aa29c5a7fb4b8f81eefe57a8b1cf5d75465d557e04b21ed7800356713ecc63b0ebbfca5", - "server_login_state": "d58815ef0bd83afafea536fe17c23f5292a5484d5748e7164b678bb4edbbfd99a31fc1b8e78ce8aab0908db29832e2c9644b4af4e3a167ab9a4f5e82c0a068eb8df23068244e4c7256c48abb28bc02529c3fbc2217c042fcc7f54e50f1516dde8f9f25c694e34604c9bea4b94090c3c911c22db5c74a79abbecf0354dc8d475575d17a1f85b7efdc2dd8b6e2fa9529bfe49d7cfa2563451fe6b9d5cd7344377c3730e197b550030c012b01466b142c9022b869fe5ea7c59412e5b6685db19997", - "password_file": "020689ce9ffba0f198d9e63e23902ff1600656fdd604aa47c289d5d073cc472354e891e7c4f89058fd270813d320e0cb97a745722eb8038eec062e5aed5e6b40b88148d43e68b7f457c352c3b6523e0bc79795f651487d007574cbaf7dba317ff8fe7d4c525bd238c501c78a7b6ab26e076bb22c6b409ca08e34875ee4055850ea0fcb59720fdb42fcbddbccbaed60a0aec01d72403c63075468e8a03c9efc25206776154291cbce05d7567a82a10d8303f991b8689643c5727b1886c478a9b8", - "export_key": "0527421cb5c31aeba8fddff1af3a673e94cbd7af57999eaed47e23ea3562d68362416d69afb3bcf450db76b4fea504d5d065e0a104d9a1848f20e64ff04f3cfd", - "session_key": "75d17a1f85b7efdc2dd8b6e2fa9529bfe49d7cfa2563451fe6b9d5cd7344377c3730e197b550030c012b01466b142c9022b869fe5ea7c59412e5b6685db19997" + "registration_request": "b889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24c", + "registration_response": "200bcd11d44e9a10541a465ed3b130d4d10632dd7433965578e33d181e321113f2f02607a409b5de08ee6e1e51ae674462397997682ea7c48c2d3c762378075b", + "registration_upload": "79d14f4164e722a8dcabffd4a341104e217d1597eeb414d4e4597d7c4376bf3b23ed2104a05b3ff4a12160f73172bbb195a3a399489bc4092e471e181a524b6c7fb6f955cacb8f8d0db54b89287b496e48b34b1a6204960925469d712c793bd89055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a9490086c367c3705a0a46a497c797de7e67c0c7d1803e17e1cfd78d949c7b8558fa46da9fb3445bdef5e285a561e04518919387726a1b73660e687bda8a14256", + "credential_request": "b889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24cc01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c169bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d", + "credential_response": "200bcd11d44e9a10541a465ed3b130d4d10632dd7433965578e33d181e321113ce8202d2438b73cfe23d5f7bccc172ee6a354d690c1770ef07f4f269978bb0dbcc6f726f243b5a331e2a5b420866413d0e8b82f391bc4183361508a9f6c1b700e5f182630556f732e466976c2797cc5b05163ee4bb6ce39b1db500f03fe365009e359199926fad26726e438722c45f11beccc0e32e45fc24732f85d1aa9543e1d7c30248a20aad34efe89f8af3e8578071aa362564b5faba808fba9a66a78a26b018aa7067155ce9bb6d2fdbc163e706888d8e0cdff1e47f45073556abc8da5a3b9470912a8c10a2bede335ddbc1198d706acca69ae6ff0a72e195d2575f5b27b32d6099439ef55837e6e817def5ee8230ffb6fcd66d0f23f7169ab49eecfa8d134f2d6db9de03c51034b3a129f84c261234429cc34dfb7afdf3e392b7962b78", + "credential_finalization": "f4133b65451a2b8f7a9cbfaca3f7c06211912fc669ffbe7cd554905b9f4e82a0e841cc97c70c8b964e02d6f665a136db0ad83b249d4f36be4c4944c4596ac696", + "client_registration_state": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0bb889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24c", + "client_login_state": "d36ed47358b72a28796b5b0fc4f9301a294659da94d394f227e6e9b8ea277c0bb889d6957f21a33951637b12f12007efc50d7b87811c96b8cc0072a605f1d24cc01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c169bbea5c768383168e385d895007f3eba4ecfbcadef26305449a76b2440465e3d388fac72f9c2e9aeeb189963015f7af1692a4a31fefaf06b4ecb66d066d9fe43c01061951b0f6acc314a0cfa2f45b8f2e2125e0f1896fa63c1d97d8f74245c16", + "server_login_state": "b87047afce3cb9166d7f96a992d423f3eebb931413775c5373dc18abd6a42f919de37ca5643454b07d84440d77d364c7dd4c9029fb481aa7e34d91f061c38c2b5ba9c3260c4eb1bdfd6ef65e1415b8e227631985d979f0c5860d3076bd8f22a0e009dd6efb4359c414257678101fe91560f15b16461ca79618c09d26f346b0e9776d5589e16dc1d9466d5aa901db05d5cbeb73c2672da3b954046b170f514ce50282b8bccc1d542e902af8486fd37f886f555e56b2f34cc91d658996651eb8b8", + "password_file": "79d14f4164e722a8dcabffd4a341104e217d1597eeb414d4e4597d7c4376bf3b23ed2104a05b3ff4a12160f73172bbb195a3a399489bc4092e471e181a524b6c7fb6f955cacb8f8d0db54b89287b496e48b34b1a6204960925469d712c793bd89055cba6082b86d8856b8ac3720c16a7ca07ff3303874149a0b5656e391bb05a9490086c367c3705a0a46a497c797de7e67c0c7d1803e17e1cfd78d949c7b8558fa46da9fb3445bdef5e285a561e04518919387726a1b73660e687bda8a14256", + "export_key": "9b728dbe104caf7ea3d52a167c74408770b89f883c4ee280ee053fd9ad5aabc62bbe78cbc6bc9230819819ea75d40b8411f914095d4101c1e0d92c71b4e5b29f", + "session_key": "776d5589e16dc1d9466d5aa901db05d5cbeb73c2672da3b954046b170f514ce50282b8bccc1d542e902af8486fd37f886f555e56b2f34cc91d658996651eb8b8" } "#; -#[cfg(all(feature = "x25519", feature = "p256"))] +#[cfg(feature = "x25519")] static TEST_VECTOR_X25519_P256: &str = r#" { - "client_s_pk": "ee6282a908e24291fcd1e7ce0a6fc244cf9b6371889e31a908d1919cdd756776", - "client_s_sk": "785f65307f77f78cc4b20565a42c1954a30763d881528749f376b90a13ca2b73", - "client_e_pk": "c6e0310d186d3c869b384418a6574cd9fff826e3a91ac46d05ce0ab56e25b978", - "client_e_sk": "e889400a32d355cd203d6a1ee195a787217db28075de794d0c39ca29c44f1776", - "server_s_pk": "1c840f081ecaa88b6eff81536d28b3220cc7101e6e90b998461cc80ead285808", - "server_s_sk": "10138ce9d5660b1b23aaf520e1ec948bd1f318b571356aa3f9becf3db34daf7a", - "server_e_pk": "152d47f6ac15e7c2c11f29bd513d182db4eed09ef3974a6e4438b72ec9aa2d0c", - "server_e_sk": "589db8b32e957d97134b10f8b2fa107b908f88eb2a4620f2ae25d61107bf9e6f", - "fake_sk": "088a857c0f23ea4896cb067420a5264e8ea22f13d6b471cc4518cdf520de817b", + "client_s_pk": "54ad295308e561e9549d2662a79a18228784bca512b50a6fd161595dbfa18f54", + "client_s_sk": "20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515b", + "client_e_pk": "07cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a", + "client_e_sk": "20bdb5e9d5d98fcd9ba5634e03eba34fc728753369ce0234c9826aa88047c259", + "server_s_pk": "4923a63bd059263cb2a69fd3a528191986d9c1f470bfe240d470af628adec277", + "server_s_sk": "88b9fbacb0d38394f61c35408fe05c6734a1a63c5e6a16684095d9cc2f82cb4d", + "server_e_pk": "e8a420fd6ff116cf865035321f91e211609b4a0f013ffd0798ea68bd04267c7a", + "server_e_sk": "20eed40939abf897bdba6d7649893a617762fb3b94e04c247a086dc48448f361", + "fake_sk": "4847b46ae57fa21f9bdf38bb4ee08ed12f64141b21707743ce3bf203cf36416b", "credential_identifier": "637265644964656e746966696572", "id_u": "696455", "id_s": "696453", "password": "70617373776f7264", - "blinding_factor": "40b461844231f2f890fc68aa0da838e25f40af01ec1b212fdf6bad07db170757", - "oprf_seed": "b25a0265e824656034824b935d49d7f844d26acf1a7d8c6c40d635543a2e6d33", - "masking_nonce": "005cf982b3ddbb28ee252d729c83c4b9d74a54ac72f25325f7f21824530649fbf165383559cce8a4734d6fcd56e45f866828008d3d4c56dd57659c80bc3e094f", - "envelope_nonce": "0c9954390a2bac0bf09c083a2152bfce397281e7a5408c08b0b18d56c0ec686c", - "client_nonce": "b389ed08bf4bfbf895ea6706c3d967b5ec7c4af96c207ebe816c50b9615ab06e", - "server_nonce": "a920b7dbb1607caea2a3d7577531fb30173d0123a2353cf4151bea9e71caaab2", + "blinding_factor": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee", + "oprf_seed": "b78f0138ef05a3df5aef410e7dda3b4972600e4d9f1e3ffa9376778cf31337ad", + "masking_nonce": "669d7a5f0b410805b4a48d81d86e821d925341c5a634581d43225b1f0820d3c13a3633d70a1eb6982b12dbca41db7718f12db87a0896034bc4c3c7c54ac4d647", + "envelope_nonce": "b57ed3206fb154fcfccb1e5effd873e9bce098af031674524c24572116061cc1", + "client_nonce": "f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef6099", + "server_nonce": "daad4ea374a85431b05253e53c5c69f67e0fc8067eaa1d492f8ff045659fe377", "context": "636f6e74657874", - "registration_request": "02c1f758572663d7bb1fa5dbc8cf426b867a9936bc741e9acc8a31b18bf0e5bd33", - "registration_response": "03068d5d3fe0d6b3361c2c728b85dce104df42d3d11c2079392ab894ace50ff4001c840f081ecaa88b6eff81536d28b3220cc7101e6e90b998461cc80ead285808", - "registration_upload": "f49b790e8f2e36ca511957263868d1ee897b2936b1ae4922ac2ad0b7a0e38f3c2606360d0008b6ed33e4ca48d31f3992875445e3a53f42e4eee661aad96e2c50785f65307f77f78cc4b20565a42c1954a30763d881528749f376b90a13ca2b7374d474b4232682bf9033067a42d35f2b9936822372cd9ea4f9b8c38b14948ff5", - "credential_request": "02c1f758572663d7bb1fa5dbc8cf426b867a9936bc741e9acc8a31b18bf0e5bd33b389ed08bf4bfbf895ea6706c3d967b5ec7c4af96c207ebe816c50b9615ab06ec6e0310d186d3c869b384418a6574cd9fff826e3a91ac46d05ce0ab56e25b978", - "credential_response": "03068d5d3fe0d6b3361c2c728b85dce104df42d3d11c2079392ab894ace50ff400005cf982b3ddbb28ee252d729c83c4b9d74a54ac72f25325f7f21824530649fbed3e1ab6eb243095958829896b0286515a108213900d019d88d8578eb7919aec225c95400fd737bdfa72a8dfcfc12958fb794383b8da8f49d13cd554569097e0f9ed325ae363061f593e3cf7a2d28ac87e5e0d2a2f344e7286cf7f38e006908b589db8b32e957d97134b10f8b2fa107b908f88eb2a4620f2ae25d61107bf9e6f3691d795831920a6728252782da676dc34b5d069d92af4d306f8b13a81185b5e8f648ff448ba49b2fbe98d0cac15fce9f60b965e79e0903bdee7528549d4241b", - "credential_finalization": "1e7f17932a85f0d16ca1a40c1233695dd23a087f17f470df4eb51e9ff24cbe43", - "client_registration_state": "40b461844231f2f890fc68aa0da838e25f40af01ec1b212fdf6bad07db17075702c1f758572663d7bb1fa5dbc8cf426b867a9936bc741e9acc8a31b18bf0e5bd33", - "client_login_state": "40b461844231f2f890fc68aa0da838e25f40af01ec1b212fdf6bad07db17075702c1f758572663d7bb1fa5dbc8cf426b867a9936bc741e9acc8a31b18bf0e5bd33b389ed08bf4bfbf895ea6706c3d967b5ec7c4af96c207ebe816c50b9615ab06ec6e0310d186d3c869b384418a6574cd9fff826e3a91ac46d05ce0ab56e25b978e889400a32d355cd203d6a1ee195a787217db28075de794d0c39ca29c44f1776b389ed08bf4bfbf895ea6706c3d967b5ec7c4af96c207ebe816c50b9615ab06e", - "server_login_state": "9a2ccb3a4690792ee4c290ae12a84049b941ac7d6c5288c300f3af40b34fef6dc40347b218e9f65fe3c67d07173dcc9d73b7bcd5e2a128e7565e4c2fcaada2c631b54a2472ce398831783222437e916804e19a67771d900cde8733e890305ce3", - "password_file": "f49b790e8f2e36ca511957263868d1ee897b2936b1ae4922ac2ad0b7a0e38f3c2606360d0008b6ed33e4ca48d31f3992875445e3a53f42e4eee661aad96e2c50785f65307f77f78cc4b20565a42c1954a30763d881528749f376b90a13ca2b7374d474b4232682bf9033067a42d35f2b9936822372cd9ea4f9b8c38b14948ff5", - "export_key": "2b867ad9909d31946cb3c3738fb1c1e51ba09d768e83d6b03eb909e0e4298003", - "session_key": "31b54a2472ce398831783222437e916804e19a67771d900cde8733e890305ce3" + "registration_request": "023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36", + "registration_response": "023e084f135edff464f60468dcc18c779ea7cea99daec254499ed082ed086bfe7d4923a63bd059263cb2a69fd3a528191986d9c1f470bfe240d470af628adec277", + "registration_upload": "fee1e2438d269807b7e8b07c5b078f553bab065deb2943ac95119ec04857dc2a8a2e3934463798e276d13a0b3456eb2a98c87968d90c4ae0a51d311fe1655d5f20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515bc4ddd82e83589cbe9c3b6fdea12acedef29aa7784a2ce0b65685dc352b66c142", + "credential_request": "023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef609907cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a", + "credential_response": "023e084f135edff464f60468dcc18c779ea7cea99daec254499ed082ed086bfe7d669d7a5f0b410805b4a48d81d86e821d925341c5a634581d43225b1f0820d3c15a700199e8446adf51b7f027b5c59ef0847b6e43ab72a6d6de4cf0eb3fe3a2093bdf8d3a50013795f094d651dcd7e9f597904e4940a3629166c2f3f4905e88c3e1f6db8f5244feebd435e5664bd395e9ba78aa93bd7e93863aa052765d4911b420eed40939abf897bdba6d7649893a617762fb3b94e04c247a086dc48448f3618e2b6d1e406e0695a0a7f32f296e45990186c54ab76a3562e7d70faf66ff99759118020c29faab346283f6e0221f7de81def8dc79c6904b5075b098a35c6a50e", + "credential_finalization": "4a6e76c08153d2c07ab695030c6fd3a6f531338e3dc85f75b0af56ee54874e2e", + "client_registration_state": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36", + "client_login_state": "1ca386b0d0a0c390c68d8eab341787260fa3ee2a94059d7887ec687eba80ceee023741a9f45d763159b728738cde140058e6bc3ead289e74b9df6cf2317dc50a36f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef609907cb52b7d96fcdcdec4ec1da39dab5210c6abca838af870886a391caf1cc9d7a20bdb5e9d5d98fcd9ba5634e03eba34fc728753369ce0234c9826aa88047c259f7e2cf7311f3bd310e331dc24a94f319c0dc5f1ae2d3a039b5da60bac9ef6099", + "server_login_state": "a4177b3ddccd8634ea0ad95dc9d7287f701fc5354ff53c84cb6205bff831fdeb49b5196d9330ab791ca1eb475a8eb04937430ef87776a7d1c7c4102231e7a1a89c599288d589338b0c99688a2db39f693d5d6f57cee46dc77f3d66af027fed3e", + "password_file": "fee1e2438d269807b7e8b07c5b078f553bab065deb2943ac95119ec04857dc2a8a2e3934463798e276d13a0b3456eb2a98c87968d90c4ae0a51d311fe1655d5f20f9d6b90a9463e8432780c647b2dd7f4becf8d174c92a8023f395d01f16515bc4ddd82e83589cbe9c3b6fdea12acedef29aa7784a2ce0b65685dc352b66c142", + "export_key": "fae7cd4aa438eeaa5f83b0a181ce29d18c9de4eecfd778a42511014c8b536f89", + "session_key": "9c599288d589338b0c99688a2db39f693d5d6f57cee46dc77f3d66af027fed3e" } "#; fn decode(values: &Value, key: &str) -> Option> { - values[key] - .as_str() - .and_then(|s| hex::decode(&s.to_string()).ok()) + values[key].as_str().and_then(|s| hex::decode(&s).ok()) } fn populate_test_vectors(values: &Value) -> TestVectorParameters { @@ -444,21 +439,24 @@ fn stringify_test_vectors(p: &TestVectorParameters) -> String { fn generate_parameters() -> Result where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // ClientRegistration: KgSk + KgPk - ::ScalarLen: Add<::ElemLen>, + as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload @@ -466,24 +464,24 @@ where NonceLen: Add<::PkLen>, Ke1MessageLen: ArrayLength, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State - ::ScalarLen: Add>, - Sum<::ScalarLen, CredentialRequestLen>: + as Group>::ScalarLen: Add>, + Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: ArrayLength + Add>, + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // Ke2Message: (Nonce + KePk) + Hash NonceLen: Add<::PkLen>, - Sum::PkLen>: ArrayLength + Add>, + Sum::PkLen>: ArrayLength + Add>>, Ke2MessageLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, @@ -506,7 +504,7 @@ where let id_s = b"idS"; let password = b"password"; let context = b"context"; - let mut oprf_seed = Output::::default(); + let mut oprf_seed = Output::>::default(); rng.fill_bytes(&mut oprf_seed); let mut masking_nonce = [0u8; 64]; rng.fill_bytes(&mut masking_nonce); @@ -517,24 +515,24 @@ where let mut server_nonce = [0u8; NonceLen::USIZE]; rng.fill_bytes(&mut server_nonce); - let fake_sk: Vec = fake_kp.private().to_vec(); + let fake_sk: Vec = fake_kp.private().serialize().to_vec(); let server_setup = ServerSetup::::deserialize( &[ oprf_seed.as_ref(), - &server_s_kp.private().to_arr(), + &server_s_kp.private().serialize(), &fake_sk, ] .concat(), ) .unwrap(); - let blinding_factor = CS::OprfGroup::random_nonzero_scalar(&mut rng); - let blinding_factor_bytes = CS::OprfGroup::scalar_as_bytes(blinding_factor); + let blinding_factor = as Group>::random_scalar(&mut rng); + let blinding_factor_bytes = OprfGroup::::serialize_scalar(blinding_factor); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec()); let client_registration_start_result = ClientRegistration::::start(&mut blinding_factor_registration_rng, password).unwrap(); - let blinding_factor_bytes_returned = CS::OprfGroup::scalar_as_bytes( + let blinding_factor_bytes_returned = OprfGroup::::serialize_scalar( client_registration_start_result .state .oprf_client @@ -557,7 +555,7 @@ where let registration_response_bytes = server_registration_start_result.message.serialize(); let mut client_s_sk_and_nonce: Vec = Vec::new(); - client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().to_arr()); + client_s_sk_and_nonce.extend_from_slice(&client_s_kp.private().serialize()); client_s_sk_and_nonce.extend_from_slice(&envelope_nonce); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); @@ -583,7 +581,7 @@ where let mut client_login_start: Vec = Vec::new(); client_login_start.extend_from_slice(&blinding_factor_bytes); - client_login_start.extend_from_slice(&client_e_kp.private().to_arr()); + client_login_start.extend_from_slice(&client_e_kp.private().serialize()); client_login_start.extend_from_slice(&client_nonce); let mut client_login_start_rng = CycleRng::new(client_login_start); @@ -595,7 +593,7 @@ where let mut server_e_sk_and_nonce_rng = CycleRng::new( [ masking_nonce.to_vec(), - server_e_kp.private().to_arr().to_vec(), + server_e_kp.private().serialize().to_vec(), server_nonce.to_vec(), ] .concat(), @@ -636,14 +634,14 @@ where let credential_finalization_bytes = client_login_finish_result.message.serialize(); Ok(TestVectorParameters { - client_s_pk: client_s_kp.public().to_arr().to_vec(), - client_s_sk: client_s_kp.private().to_arr().to_vec(), - client_e_pk: client_e_kp.public().to_arr().to_vec(), - client_e_sk: client_e_kp.private().to_arr().to_vec(), - server_s_pk: server_s_kp.public().to_arr().to_vec(), - server_s_sk: server_s_kp.private().to_arr().to_vec(), - server_e_pk: server_e_kp.public().to_arr().to_vec(), - server_e_sk: server_e_kp.private().to_arr().to_vec(), + client_s_pk: client_s_kp.public().to_bytes().to_vec(), + client_s_sk: client_s_kp.private().serialize().to_vec(), + client_e_pk: client_e_kp.public().to_bytes().to_vec(), + client_e_sk: client_e_kp.private().serialize().to_vec(), + server_s_pk: server_s_kp.public().to_bytes().to_vec(), + server_s_sk: server_s_kp.private().serialize().to_vec(), + server_e_pk: server_e_kp.public().to_bytes().to_vec(), + server_e_sk: server_e_kp.private().serialize().to_vec(), fake_sk, credential_identifier: credential_identifier.to_vec(), id_u: id_u.to_vec(), @@ -678,11 +676,10 @@ fn generate_test_vectors() -> Result<(), ProtocolError> { let parameters = generate_parameters::()?; println!("Ristretto255: {}", stringify_test_vectors(¶meters)); } - #[cfg(feature = "p256")] - { - let parameters = generate_parameters::()?; - println!("P-256: {}", stringify_test_vectors(¶meters)); - } + + let parameters = generate_parameters::()?; + println!("P-256: {}", stringify_test_vectors(¶meters)); + #[cfg(all(feature = "x25519", feature = "ristretto255"))] { let parameters = generate_parameters::()?; @@ -691,7 +688,8 @@ fn generate_test_vectors() -> Result<(), ProtocolError> { stringify_test_vectors(¶meters) ); } - #[cfg(all(feature = "x25519", feature = "p256"))] + + #[cfg(feature = "x25519")] { let parameters = generate_parameters::()?; println!("X25519 P-256: {}", stringify_test_vectors(¶meters)); @@ -704,11 +702,14 @@ fn generate_test_vectors() -> Result<(), ProtocolError> { fn test_registration_request() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // ClientRegistration: KgSk + KgPk - ::ScalarLen: Add<::ElemLen>, + as Group>::ScalarLen: Add< as Group>::ElemLen>, ClientRegistrationLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -728,11 +729,10 @@ fn test_registration_request() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -745,9 +745,12 @@ fn test_serialization() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let mut rng = CycleRng::new(parameters.blinding_factor.to_vec()); @@ -773,11 +776,10 @@ fn test_serialization() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -787,11 +789,14 @@ fn test_serialization() -> Result<(), ProtocolError> { fn test_registration_response() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, { let parameters = populate_test_vectors( @@ -821,11 +826,10 @@ fn test_registration_response() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -835,15 +839,18 @@ fn test_registration_response() -> Result<(), ProtocolError> { fn test_registration_upload() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { @@ -874,7 +881,7 @@ fn test_registration_upload() -> Result<(), ProtocolError> { ); assert_eq!( hex::encode(parameters.export_key), - hex::encode(result.export_key.to_vec()) + hex::encode(result.export_key) ); Ok(()) @@ -882,11 +889,10 @@ fn test_registration_upload() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -896,15 +902,18 @@ fn test_registration_upload() -> Result<(), ProtocolError> { fn test_password_file() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload @@ -924,11 +933,10 @@ fn test_password_file() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -938,15 +946,18 @@ fn test_password_file() -> Result<(), ProtocolError> { fn test_credential_request() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State - ::ScalarLen: Add>, - Sum<::ScalarLen, CredentialRequestLen>: + as Group>::ScalarLen: Add>, + Sum< as Group>::ScalarLen, CredentialRequestLen>: ArrayLength + Add>, ClientLoginLen: ArrayLength, { @@ -974,11 +985,10 @@ fn test_credential_request() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -988,16 +998,20 @@ fn test_credential_request() -> Result<(), ProtocolError> { fn test_credential_response() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message @@ -1050,11 +1064,10 @@ fn test_credential_response() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -1064,12 +1077,16 @@ fn test_credential_response() -> Result<(), ProtocolError> { fn test_credential_finalization() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -1090,7 +1107,7 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { assert_eq!( hex::encode(¶meters.server_s_pk), - hex::encode(&client_login_finish_result.server_s_pk.to_arr().to_vec()) + hex::encode(&client_login_finish_result.server_s_pk.to_bytes()) ); assert_eq!( hex::encode(¶meters.session_key), @@ -1110,11 +1127,10 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -1124,9 +1140,12 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { fn test_server_login_finish() -> Result<(), ProtocolError> { fn inner(test_vector: &str) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -1145,11 +1164,10 @@ fn test_server_login_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; - #[cfg(feature = "p256")] inner::(TEST_VECTOR_P256)?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::(TEST_VECTOR_X25519_P256)?; Ok(()) @@ -1160,12 +1178,15 @@ fn test_complete_flow( login_password: &[u8], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let credential_identifier = b"credentialIdentifier"; @@ -1230,11 +1251,10 @@ where fn test_complete_flow_success() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] test_complete_flow::(b"good password", b"good password")?; - #[cfg(feature = "p256")] test_complete_flow::(b"good password", b"good password")?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] test_complete_flow::(b"good password", b"good password")?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] test_complete_flow::(b"good password", b"good password")?; Ok(()) @@ -1244,11 +1264,10 @@ fn test_complete_flow_success() -> Result<(), ProtocolError> { fn test_complete_flow_fail() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] test_complete_flow::(b"good password", b"bad password")?; - #[cfg(feature = "p256")] test_complete_flow::(b"good password", b"bad password")?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] test_complete_flow::(b"good password", b"bad password")?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] test_complete_flow::(b"good password", b"bad password")?; Ok(()) @@ -1260,16 +1279,19 @@ fn test_complete_flow_fail() -> Result<(), ProtocolError> { fn test_zeroize_client_registration_start() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut client_rng = OsRng; let client_registration_start_result = ClientRegistration::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let mut state = client_registration_start_result.state; - Zeroize::zeroize(&mut state); + unsafe { ptr::drop_in_place(&mut state) }; for byte in state.to_vec() { assert_eq!(byte, 0); } @@ -1279,11 +1301,10 @@ fn test_zeroize_client_registration_start() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1293,9 +1314,12 @@ fn test_zeroize_client_registration_start() -> Result<(), ProtocolError> { fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let mut client_rng = OsRng; let mut server_rng = OsRng; @@ -1315,7 +1339,7 @@ fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { )?; let mut state = client_registration_finish_result.state; - Zeroize::zeroize(&mut state); + unsafe { ptr::drop_in_place(&mut state) }; for byte in state.to_vec() { assert_eq!(byte, 0); } @@ -1325,11 +1349,10 @@ fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1339,15 +1362,18 @@ fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload @@ -1371,21 +1397,19 @@ fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> { let p_file = ServerRegistration::finish(client_registration_finish_result.message); let mut state = p_file; - Zeroize::zeroize(&mut state); - for byte in state.serialize() { - assert_eq!(byte, 0); - } + util::drop_manually(&mut state); + util::test_zeroized(&mut state.0.envelope.mode); + util::test_zeroized(&mut state.0.masking_key); Ok(()) } #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1393,35 +1417,55 @@ fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> { #[test] fn test_zeroize_client_login_start() -> Result<(), ProtocolError> { - fn inner() -> Result<(), ProtocolError> + fn inner>() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add::PkLen>>, CredentialRequestLen: ArrayLength, + // Ke1State: KeSk + Nonce + ::SkLen: Add, + Sum<::SkLen, NonceLen>: ArrayLength, + // Ke1Message: Nonce + KePk + NonceLen: Add<::PkLen>, + Sum::PkLen>: ArrayLength, + // Ke2State: (Hash + Hash) + Hash + OutputSize>: Add>>, + Sum>, OutputSize>>: + ArrayLength + Add>>, + Sum>, OutputSize>>, OutputSize>>: + ArrayLength, + // Ke2Message: (Nonce + KePk) + Hash + NonceLen: Add<::PkLen>, + Sum::PkLen>: + ArrayLength + Add>>, + Sum::PkLen>, OutputSize>>: + ArrayLength, { let mut client_rng = OsRng; let client_login_start_result = ClientLogin::::start(&mut client_rng, STR_PASSWORD.as_bytes())?; let mut state = client_login_start_result.state; - Zeroize::zeroize(&mut state); - for byte in state.to_vec() { - assert_eq!(byte, 0); - } + util::drop_manually(&mut state); + util::test_zeroized(&mut state.oprf_client); + util::test_zeroized(&mut state.ke1_state); + util::test_zeroized(&mut state.credential_request.ke1_message.client_nonce); Ok(()) } #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1431,12 +1475,16 @@ fn test_zeroize_client_login_start() -> Result<(), ProtocolError> { fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut client_rng = OsRng; @@ -1468,7 +1516,7 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { )?; let mut state = server_login_start_result.state; - Zeroize::zeroize(&mut state); + unsafe { ptr::drop_in_place(&mut state) }; for byte in state.serialize() { assert_eq!(byte, 0); } @@ -1478,11 +1526,10 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1490,18 +1537,40 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { #[test] fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { - fn inner() -> Result<(), ProtocolError> + fn inner>() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add::PkLen>>, CredentialRequestLen: ArrayLength, + // Ke1State: KeSk + Nonce + ::SkLen: Add, + Sum<::SkLen, NonceLen>: ArrayLength, + // Ke1Message: Nonce + KePk + NonceLen: Add<::PkLen>, + Sum::PkLen>: ArrayLength, + // Ke2State: (Hash + Hash) + Hash + OutputSize>: Add>>, + Sum>, OutputSize>>: + ArrayLength + Add>>, + Sum>, OutputSize>>, OutputSize>>: + ArrayLength, + // Ke2Message: (Nonce + KePk) + Hash + NonceLen: Add<::PkLen>, + Sum::PkLen>: + ArrayLength + Add>>, + Sum::PkLen>, OutputSize>>: + ArrayLength, { let mut client_rng = OsRng; let mut server_rng = OsRng; @@ -1537,21 +1606,20 @@ fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { )?; let mut state = client_login_finish_result.state; - Zeroize::zeroize(&mut state); - for byte in state.to_vec() { - assert_eq!(byte, 0); - } + util::drop_manually(&mut state); + util::test_zeroized(&mut state.oprf_client); + util::test_zeroized(&mut state.ke1_state); + util::test_zeroized(&mut state.credential_request.ke1_message.client_nonce); Ok(()) } #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1561,12 +1629,16 @@ fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let mut client_rng = OsRng; @@ -1606,7 +1678,7 @@ fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { .finish(client_login_finish_result.message)?; let mut state = server_login_finish_result.state; - Zeroize::zeroize(&mut state); + unsafe { ptr::drop_in_place(&mut state) }; for byte in state.serialize() { assert_eq!(byte, 0); } @@ -1616,11 +1688,10 @@ fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1630,9 +1701,12 @@ fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { // Start out with a bunch of zeros to force resampling of scalar let mut client_registration_rng = CycleRng::new([vec![0u8; 128], vec![1u8; 128]].concat()); @@ -1640,7 +1714,7 @@ fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { ClientRegistration::::start(&mut client_registration_rng, STR_PASSWORD.as_bytes())?; assert!(!bool::from( - CS::OprfGroup::identity().ct_eq( + OprfGroup::::identity_elem().ct_eq( &client_registration_start_result .message .get_blinded_element_for_testing() @@ -1654,7 +1728,7 @@ fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { ClientLogin::::start(&mut client_login_rng, STR_PASSWORD.as_bytes())?; assert!(!bool::from( - CS::OprfGroup::identity().ct_eq( + OprfGroup::::identity_elem().ct_eq( &client_login_start_result .message .get_blinded_element_for_testing() @@ -1667,11 +1741,10 @@ fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1681,9 +1754,12 @@ fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { let credential_identifier = b"credentialIdentifier"; let password = b"password"; @@ -1723,11 +1799,10 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) @@ -1737,12 +1812,16 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { fn test_reflected_value_error_login() -> Result<(), ProtocolError> { fn inner() -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: + ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { let credential_identifier = b"credentialIdentifier"; @@ -1797,11 +1876,10 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; - #[cfg(feature = "p256")] inner::()?; #[cfg(all(feature = "x25519", feature = "ristretto255"))] inner::()?; - #[cfg(all(feature = "x25519", feature = "p256"))] + #[cfg(feature = "x25519")] inner::()?; Ok(()) diff --git a/src/tests/test_opaque_vectors.rs b/src/tests/test_opaque_vectors.rs old mode 100755 new mode 100644 index 7c2e9a0a..c194790c --- a/src/tests/test_opaque_vectors.rs +++ b/src/tests/test_opaque_vectors.rs @@ -6,20 +6,22 @@ // of this source tree. use core::ops::Add; -use std::string::ToString; use std::vec::Vec; use std::{println, vec}; use digest::core_api::{BlockSizeUser, CoreProxy}; -use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256}; -use generic_array::ArrayLength; +use digest::OutputSizeUser; +use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, U256}; +use generic_array::{ArrayLength, GenericArray}; use json::JsonValue; +use rand::rngs::OsRng; +use rand::RngCore; use voprf::Group; -use crate::ciphersuite::CipherSuite; +use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash}; use crate::envelope::EnvelopeLen; use crate::errors::*; -use crate::hash::{OutputSize, ProxyHash}; +use crate::hash::{Hash, OutputSize, ProxyHash}; use crate::key_exchange::group::KeGroup; use crate::key_exchange::traits::{Ke1MessageLen, Ke2MessageLen}; use crate::key_exchange::tripledh::{NonceLen, TripleDH}; @@ -89,30 +91,39 @@ macro_rules! parse_default { }; } -/// If no entry is found, default to filling a random buffer of a specified size -macro_rules! parse_default_random { - ( $v:ident, $s:expr, $size:expr ) => { - parse_default!($v, $s, { - use rand::rngs::OsRng; - use rand::RngCore; - let mut rng = OsRng; - let mut v = vec![0u8; $size]; - rng.fill_bytes(&mut v); - v - }) - }; -} - fn decode(values: &JsonValue, key: &str) -> Option> { - values[key] - .as_str() - .and_then(|s| hex::decode(&s.to_string()).ok()) + values[key].as_str().and_then(|s| hex::decode(&s).ok()) } -fn populate_test_vectors(values: &JsonValue) -> OpaqueTestVectorParameters { +fn populate_test_vectors(values: &JsonValue) -> OpaqueTestVectorParameters +where + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + let mut rng = OsRng; + OpaqueTestVectorParameters { - dummy_private_key: parse_default_random!(values, "client_private_key", 32), - dummy_masking_key: parse_default_random!(values, "masking_key", 64), + dummy_private_key: { + match decode(values, "client_private_key") { + Some(value) => value, + None => CS::KeGroup::serialize_sk(&CS::KeGroup::random_sk(&mut OsRng)).to_vec(), + } + }, + dummy_masking_key: { + match decode(values, "masking_key") { + Some(value) => value, + None => { + let mut bytes = + GenericArray:: as OutputSizeUser>::OutputSize>::default(); + rng.fill_bytes(&mut bytes); + bytes.to_vec() + } + } + }, context: parse!(values, "Context"), client_private_key: decode(values, "client_private_key"), client_keyshare: parse!(values, "client_keyshare"), @@ -153,15 +164,18 @@ fn populate_test_vectors(values: &JsonValue) -> OpaqueTestVectorParameters { fn get_password_file_bytes(parameters: &OpaqueTestVectorParameters) -> Vec where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload @@ -174,12 +188,12 @@ where } macro_rules! json_to_test_vectors { - ( $v:ident, $vector_type:expr, $cs:expr, ) => { + ( $v:ident, $vector_type:expr, $cs:expr, $cs_ty:ty) => { $v[$vector_type] .members() .filter_map(|x| { if x.has_key($cs) { - Some(populate_test_vectors(&x[$cs])) + Some(populate_test_vectors::<$cs_ty>(&x[$cs])) } else { None } @@ -195,24 +209,33 @@ fn tests() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] { - let ristretto_real_tvs = json_to_test_vectors!(rfc, "Real", "ristretto255, SHA512",); + struct Ristretto255Sha512NoSlowHash; + impl CipherSuite for Ristretto255Sha512NoSlowHash { + type OprfGroup = crate::Ristretto255; + type KeGroup = crate::Ristretto255; + type KeyExchange = TripleDH; + type SlowHash = NoOpHash; + } + + let ristretto_real_tvs = json_to_test_vectors!( + rfc, + "Real", + "ristretto255, SHA512", + Ristretto255Sha512NoSlowHash + ); - let ristretto_fake_tvs = json_to_test_vectors!(rfc, "Fake", "ristretto255, SHA512",); + let ristretto_fake_tvs = json_to_test_vectors!( + rfc, + "Fake", + "ristretto255, SHA512", + Ristretto255Sha512NoSlowHash + ); assert!( !(ristretto_real_tvs.is_empty() || ristretto_fake_tvs.is_empty()), "Parsing error" ); - struct Ristretto255Sha512NoSlowHash; - impl CipherSuite for Ristretto255Sha512NoSlowHash { - type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeGroup = curve25519_dalek::ristretto::RistrettoPoint; - type KeyExchange = TripleDH; - type Hash = sha2::Sha512; - type SlowHash = NoOpHash; - } - test_registration_request::(&ristretto_real_tvs)?; test_registration_response::(&ristretto_real_tvs)?; test_registration_upload::(&ristretto_real_tvs)?; @@ -223,36 +246,40 @@ fn tests() -> Result<(), ProtocolError> { test_fake_vectors::(&ristretto_fake_tvs)?; } - #[cfg(feature = "p256")] - { - let p256_real_tvs = - json_to_test_vectors!(rfc, "Real", "P256_XMD:SHA-256_SSWU_RO_, SHA256",); - let p256_fake_tvs = - json_to_test_vectors!(rfc, "Fake", "P256_XMD:SHA-256_SSWU_RO_, SHA256",); + struct P256Sha256NoSlowHash; + impl CipherSuite for P256Sha256NoSlowHash { + type OprfGroup = p256::NistP256; + type KeGroup = p256::NistP256; + type KeyExchange = TripleDH; + type SlowHash = NoOpHash; + } - assert!( - !(p256_real_tvs.is_empty() || p256_fake_tvs.is_empty()), - "Parsing error" - ); + let p256_real_tvs = json_to_test_vectors!( + rfc, + "Real", + "P256_XMD:SHA-256_SSWU_RO_, SHA256", + P256Sha256NoSlowHash + ); + let p256_fake_tvs = json_to_test_vectors!( + rfc, + "Fake", + "P256_XMD:SHA-256_SSWU_RO_, SHA256", + P256Sha256NoSlowHash + ); - struct P256Sha256NoSlowHash; - impl CipherSuite for P256Sha256NoSlowHash { - type OprfGroup = p256_::ProjectivePoint; - type KeGroup = p256_::PublicKey; - type KeyExchange = TripleDH; - type Hash = sha2::Sha256; - type SlowHash = NoOpHash; - } + assert!( + !(p256_real_tvs.is_empty() || p256_fake_tvs.is_empty()), + "Parsing error" + ); - test_registration_request::(&p256_real_tvs)?; - test_registration_response::(&p256_real_tvs)?; - test_registration_upload::(&p256_real_tvs)?; - test_ke1::(&p256_real_tvs)?; - test_ke2::(&p256_real_tvs)?; - test_ke3::(&p256_real_tvs)?; - test_server_login_finish::(&p256_real_tvs)?; - test_fake_vectors::(&p256_fake_tvs)?; - } + test_registration_request::(&p256_real_tvs)?; + test_registration_response::(&p256_real_tvs)?; + test_registration_upload::(&p256_real_tvs)?; + test_ke1::(&p256_real_tvs)?; + test_ke2::(&p256_real_tvs)?; + test_ke3::(&p256_real_tvs)?; + test_server_login_finish::(&p256_real_tvs)?; + test_fake_vectors::(&p256_fake_tvs)?; Ok(()) } @@ -261,9 +288,12 @@ fn test_registration_request( tvs: &[OpaqueTestVectorParameters], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { for parameters in tvs { let mut rng = CycleRng::new(parameters.blind_registration.to_vec()); @@ -281,11 +311,14 @@ fn test_registration_response( tvs: &[OpaqueTestVectorParameters], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // RegistrationResponse: KgPk + KePk - ::ElemLen: Add<::PkLen>, + as Group>::ElemLen: Add<::PkLen>, RegistrationResponseLen: ArrayLength, { for parameters in tvs { @@ -318,15 +351,18 @@ fn test_registration_upload( tvs: &[OpaqueTestVectorParameters], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, { @@ -362,7 +398,7 @@ where ); assert_eq!( hex::encode(¶meters.export_key), - hex::encode(result.export_key.to_vec()) + hex::encode(result.export_key) ); } @@ -371,11 +407,14 @@ where fn test_ke1(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // CredentialRequest: KgPk + Ke1Message - ::ElemLen: Add>, + as Group>::ElemLen: Add>, CredentialRequestLen: ArrayLength, { for parameters in tvs { @@ -404,29 +443,32 @@ where fn test_ke2(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: ArrayLength + Add>, + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, @@ -489,12 +531,15 @@ where fn test_ke3(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { for parameters in tvs { @@ -549,21 +594,24 @@ fn test_server_login_finish( tvs: &[OpaqueTestVectorParameters], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // Envelope: Nonce + Hash - NonceLen: Add>, + NonceLen: Add>>, EnvelopeLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope - ::PkLen: Add>, - Sum<::PkLen, OutputSize>: + ::PkLen: Add>>, + Sum<::PkLen, OutputSize>>: ArrayLength + Add>, RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, { for parameters in tvs { @@ -618,16 +666,19 @@ fn test_fake_vectors( tvs: &[OpaqueTestVectorParameters], ) -> Result<(), ProtocolError> where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + as OutputSizeUser>::OutputSize: + IsLess + IsLessOrEqual< as BlockSizeUser>::BlockSize>, + OprfHash: Hash, + as CoreProxy>::Core: ProxyHash, + < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, + Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, // MaskedResponse: (Nonce + Hash) + KePk - NonceLen: Add>, - Sum>: ArrayLength + Add<::PkLen>, + NonceLen: Add>>, + Sum>>: ArrayLength + Add<::PkLen>, MaskedResponseLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - ::ElemLen: Add, - Sum<::ElemLen, NonceLen>: ArrayLength + Add>, + as Group>::ElemLen: Add, + Sum< as Group>::ElemLen, NonceLen>: ArrayLength + Add>, CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 00000000..2aaff7d9 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,41 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under both the MIT license found in the +// LICENSE-MIT file in the root directory of this source tree and the Apache +// License, Version 2.0 found in the LICENSE-APACHE file in the root directory +// of this source tree. + +//! Utility functions. + +#[cfg(test)] +pub(crate) fn test_zeroize_on_drop(value: &mut T) { + drop_manually(value); + + test_zeroized(value); +} + +#[cfg(test)] +pub(crate) fn test_zeroized(value: &mut T) { + use std::{mem, slice, vec}; + + let test = + unsafe { slice::from_raw_parts(value as *const _ as *const u8, mem::size_of::()) }; + + assert_eq!(test, vec![0; mem::size_of::()]); +} + +#[cfg(test)] +pub(crate) fn drop_manually(value: &mut T) { + use std::{mem, ptr, vec}; + + assert!(mem::needs_drop::()); + let mut test_holder = vec![value]; + let ptr = &mut *test_holder[0] as *mut T; + + unsafe { + test_holder.set_len(0); + ptr::drop_in_place(ptr); + } + + assert_eq!(test_holder.capacity(), 1); +}