Group revamp (#261)

* Revamp `KeGroup` trait

* Update dependencies

* Fix `hash_to_scalar` using `OprfGroup` instead of `KeGroup`

* Relax constraints on associated types of `KeGroup`

* Improve `KeGroup` implementation on `Curve`

* Improve `KeyExchange` trait

* Fix new Clippy 1.59 warnings
This commit is contained in:
daxpedda
2022-02-24 22:13:22 -08:00
committed by GitHub
parent 47a26a19c5
commit b2f10858e0
28 changed files with 2133 additions and 1574 deletions
+42 -51
View File
@@ -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
Executable → Regular
+33 -40
View File
@@ -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" }
+1 -1
View File
@@ -27,7 +27,7 @@ opaque-ke = "0.6.0"
### Minimum Supported Rust Version
Rust **1.56** or higher.
Rust **1.57** or higher.
Audit
-----
+5 -7
View File
@@ -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;
}
+4 -6
View File
@@ -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;
}
+4 -6
View File
@@ -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;
}
Executable → Regular
View File
+14 -11
View File
@@ -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
<Self::Hash as CoreProxy>::Core: ProxyHash,
<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<Self> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<Self> as BlockSizeUser>::BlockSize>,
OprfHash<Self>: Hash,
<OprfHash<Self> as CoreProxy>::Core: ProxyHash,
<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// 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<Self::Hash, Self::KeGroup>;
/// The main hash function use (for HKDF computations and hashing
/// transcripts)
type Hash: Hash;
type KeyExchange: KeyExchange<OprfHash<Self>, Self::KeGroup>;
/// A slow hashing function, typically used for password hashing
type SlowHash: SlowHash<Self::Hash>;
type SlowHash: SlowHash;
}
pub(crate) type OprfGroup<CS> = <<CS as CipherSuite>::OprfGroup as voprf::CipherSuite>::Group;
pub(crate) type OprfHash<CS> = <<CS as CipherSuite>::OprfGroup as voprf::CipherSuite>::Hash;
Executable → Regular
+111 -64
View File
@@ -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<u8> for InnerEnvelopeMode {
type Error = ProtocolError;
fn try_from(x: u8) -> Result<Self, Self::Error> {
@@ -61,17 +65,46 @@ impl TryFrom<u8> 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<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
mode: InnerEnvelopeMode,
pub(crate) mode: InnerEnvelopeMode,
nonce: GenericArray<u8, NonceLen>,
hmac: Output<CS::Hash>,
hmac: Output<OprfHash<CS>>,
}
impl<CS: CipherSuite> Drop for Envelope<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.mode.zeroize();
self.nonce.zeroize();
self.hmac.zeroize();
}
}
impl<CS: CipherSuite> ZeroizeOnDrop for Envelope<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) client_static_keypair: KeyPair<CS::KeGroup>,
pub(crate) export_key: Output<CS::Hash>,
pub(crate) export_key: Output<OprfHash<CS>>,
pub(crate) id_u: Serialize<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
pub(crate) id_s: Serialize<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
}
@@ -100,31 +136,34 @@ where
}
#[cfg(not(test))]
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<CS::Hash>);
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<OprfHash<CS>>);
#[cfg(test)]
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<CS::Hash>, Output<CS::Hash>);
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<OprfHash<CS>>, Output<OprfHash<CS>>);
#[cfg(not(test))]
type SealResult<CS: CipherSuite> = (Envelope<CS>, PublicKey<CS::KeGroup>, Output<CS::Hash>);
type SealResult<CS: CipherSuite> = (Envelope<CS>, PublicKey<CS::KeGroup>, Output<OprfHash<CS>>);
#[cfg(test)]
type SealResult<CS: CipherSuite> = (
Envelope<CS>,
PublicKey<CS::KeGroup>,
Output<CS::Hash>,
Output<CS::Hash>,
Output<OprfHash<CS>>,
Output<OprfHash<CS>>,
);
pub(crate) type EnvelopeLen<CS: CipherSuite> = Sum<NonceLen, OutputSize<CS::Hash>>;
pub(crate) type EnvelopeLen<CS: CipherSuite> = Sum<NonceLen, OutputSize<OprfHash<CS>>>;
impl<CS: CipherSuite> Envelope<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
#[allow(clippy::type_complexity)]
pub(crate) fn seal<R: RngCore + CryptoRng>(
rng: &mut R,
randomized_pwd_hasher: Hkdf<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
server_s_pk: &PublicKey<CS::KeGroup>,
ids: Identifiers,
) -> Result<SealResult<CS>, ProtocolError> {
@@ -136,12 +175,13 @@ where
build_inner_envelope_internal::<CS>(randomized_pwd_hasher.clone(), nonce)?,
);
let server_s_pk_bytes = server_s_pk.to_bytes();
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
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<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
aad: impl Iterator<Item = &'a [u8]>,
mode: InnerEnvelopeMode,
) -> Result<SealRawResult<CS>, InternalError> {
let mut hmac_key = Output::<CS::Hash>::default();
let mut export_key = Output::<CS::Hash>::default();
let mut hmac_key = Output::<OprfHash<CS>>::default();
let mut export_key = Output::<OprfHash<CS>>::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::<CS::Hash>::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?;
let mut hmac = Hmac::<OprfHash<CS>>::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<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
server_s_pk: PublicKey<CS::KeGroup>,
optional_ids: Identifiers<'a>,
) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> {
@@ -206,12 +246,13 @@ where
}
};
let server_s_pk_bytes = server_s_pk.to_bytes();
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
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<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
aad: impl Iterator<Item = &'a [u8]>,
) -> Result<OpenedInnerEnvelope<CS::Hash>, InternalError> {
let mut hmac_key = Output::<CS::Hash>::default();
let mut export_key = Output::<CS::Hash>::default();
) -> Result<OpenedInnerEnvelope<OprfHash<CS>>, InternalError> {
let mut hmac_key = Output::<OprfHash<CS>>::default();
let mut export_key = Output::<OprfHash<CS>>::default();
randomized_pwd_hasher
.expand(&self.nonce.concat(STR_AUTH_KEY.into()), &mut hmac_key)
@@ -240,8 +281,8 @@ where
.expand(&self.nonce.concat(STR_EXPORT_KEY.into()), &mut export_key)
.map_err(|_| InternalError::HkdfError)?;
let mut hmac =
Hmac::<CS::Hash>::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?;
let mut hmac = Hmac::<OprfHash<CS>>::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::<CS::Hash>::USIZE
OutputSize::<OprfHash<CS>>::USIZE
}
pub(crate) fn len() -> usize {
OutputSize::<CS::Hash>::USIZE + NonceLen::USIZE
OutputSize::<OprfHash<CS>>::USIZE + NonceLen::USIZE
}
pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>>
where
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
{
self.nonce.concat(self.hmac.clone())
@@ -305,22 +346,25 @@ where
// Helper functions
fn build_inner_envelope_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
) -> Result<PublicKey<CS::KeGroup>, ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut keypair_seed = GenericArray::<_, <CS::KeGroup as KeGroup>::SkLen>::default();
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
&CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash, _, _>(
[keypair_seed.as_slice()],
GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
)?;
@@ -328,22 +372,25 @@ where
}
fn recover_keys_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<CS::Hash>,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>,
) -> Result<KeyPair<CS::KeGroup>, ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut keypair_seed = GenericArray::<_, <CS::KeGroup as KeGroup>::SkLen>::default();
randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?;
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
&CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash, _, _>(
[keypair_seed.as_slice()],
GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
&[keypair_seed.as_slice()],
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
)?),
)?;
+16 -12
View File
@@ -31,8 +31,8 @@ pub enum InternalError<T = Infallible> {
},
/// 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<T = Infallible> {
/** 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<T: Debug> Debug for InternalError<T> {
@@ -69,7 +67,7 @@ impl<T: Debug> Debug for InternalError<T> {
.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<T: Debug> Debug for InternalError<T> {
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<voprf::Error> for ProtocolError {
}
}
impl From<voprf::InternalError> 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<T = Infallible> {
Executable → Regular
+24 -12
View File
@@ -11,9 +11,12 @@ macro_rules! impl_serialize_and_deserialize_for {
#[cfg(feature = "serde")]
impl<CS: CipherSuite> serde_::Serialize for $item<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
$($($path: $bound1 $(+ $bound2)*),+)?
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -27,9 +30,12 @@ macro_rules! impl_serialize_and_deserialize_for {
#[cfg(feature = "serde")]
impl<'de, CS: CipherSuite> serde_::Deserialize<'de> for $item<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -39,15 +45,21 @@ macro_rules! impl_serialize_and_deserialize_for {
struct ByteVisitor<CS: CipherSuite>(core::marker::PhantomData<CS>)
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
impl<'de, CS: CipherSuite> serde_::de::Visitor<'de> for ByteVisitor<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
type Value = $item<CS>;
+85
View File
@@ -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<G: Curve + GroupDigest + ProjectiveArithmetic> KeGroup for G
where
FieldSize<Self>: ModulusSize,
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
Scalar<Self>: FromOkm,
{
type Pk = PublicKey<Self>;
type PkLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize;
type Sk = SecretKey<Self>;
type SkLen = FieldSize<Self>;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(pk.to_encoded_point(true).as_bytes())
}
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
PublicKey::from_sec1_bytes(bytes).map_err(|_| InternalError::PointError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
SecretKey::random(rng)
}
// Implements the `HashToScalar()` function
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
Self::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
.ok()
.and_then(|scalar| Option::<NonZeroScalar<Self>>::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<u8, Self::PkLen> {
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<u8, Self::SkLen> {
sk.to_be_bytes()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> {
SecretKey::from_be_bytes(bytes).map_err(|_| InternalError::PointError)
}
}
+46 -21
View File
@@ -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<u8> + 'static;
type PkLen: ArrayLength<u8>;
/// Secret key
type Sk: Clone;
/// Length of the secret key
type SkLen: ArrayLength<u8> + 'static;
/// Return a public key from its fixed-length bytes representation
fn from_pk_slice(element_bits: &GenericArray<u8, Self::PkLen>) -> Result<Self, InternalError>;
/// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, Self::SkLen>;
/// Return a public key from its secret key
fn public_key(sk: &GenericArray<u8, Self::SkLen>) -> Self;
type SkLen: ArrayLength<u8>;
/// Serializes `self`
fn to_arr(&self) -> GenericArray<u8, Self::PkLen>;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen>;
/// Return a public key from its fixed-length bytes representation
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError>;
/// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(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<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Return a public key from its secret key
fn public_key(sk: &Self::Sk) -> Self::Pk;
/// Diffie-Hellman key exchange
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::PkLen>;
}
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen>;
#[cfg(feature = "p256")]
pub mod p256;
#[cfg(feature = "ristretto255")]
pub mod ristretto255;
#[cfg(feature = "x25519")]
pub mod x25519;
/// Zeroize secret key on drop.
fn zeroize_sk_on_drop(sk: &mut Self::Sk);
/// Serializes `self`
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen>;
/// Return a public key from its fixed-length bytes representation
fn deserialize_sk(bytes: &GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>;
}
-52
View File
@@ -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<NistP256> {
type PkLen = U33;
type SkLen = U32;
fn from_pk_slice(element_bits: &GenericArray<u8, Self::PkLen>) -> Result<Self, InternalError> {
Self::from_sec1_bytes(element_bits).map_err(|_| InternalError::PointError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, Self::SkLen> {
SecretKey::<NistP256>::random(rng).to_be_bytes()
}
fn public_key(sk: &GenericArray<u8, Self::SkLen>) -> Self {
SecretKey::<NistP256>::from_be_bytes(sk)
.unwrap()
.public_key()
}
fn to_arr(&self) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(self.to_encoded_point(true).as_bytes())
}
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::PkLen> {
(self.to_projective()
* SecretKey::<NistP256>::from_be_bytes(sk)
.unwrap()
.to_nonzero_scalar()
.as_ref())
.to_affine()
.to_bytes()
}
}
+129 -13
View File
@@ -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<u8, Self::PkLen>) -> Result<Self, InternalError> {
CompressedRistretto::from_slice(element_bits)
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
pk.compress().to_bytes().into()
}
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
CompressedRistretto::from_slice(bytes)
.decompress()
.ok_or(InternalError::PointError)
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, Self::SkLen> {
fn random_sk<R: RngCore + CryptoRng>(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<u8, Self::SkLen>) -> 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<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
ExpandMsgXmd::<H>::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 to_arr(&self) -> GenericArray<u8, Self::PkLen> {
self.compress().to_bytes().into()
fn public_key(sk: &Self::Sk) -> Self::Pk {
RISTRETTO_BASEPOINT_POINT * sk
}
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::SkLen> {
(self * Scalar::from_bits(*sk.as_ref())).to_arr()
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
Self::serialize_pk(&(pk * sk))
}
fn zeroize_sk_on_drop(sk: &mut Self::Sk) {
sk.zeroize()
}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes().into()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Sk, InternalError> {
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 = <voprf::Ristretto255 as voprf::CipherSuite>::Group;
type Hash = <voprf::Ristretto255 as voprf::CipherSuite>::Hash;
}
impl Group for Ristretto255 {
type Elem = <voprf::Ristretto255 as Group>::Elem;
type ElemLen = <voprf::Ristretto255 as Group>::ElemLen;
type Scalar = <voprf::Ristretto255 as Group>::Scalar;
type ScalarLen = <voprf::Ristretto255 as Group>::ScalarLen;
fn hash_to_curve<CS: voprf::CipherSuite>(
input: &[&[u8]],
dst: &[u8],
) -> voprf::Result<Self::Elem, voprf::InternalError>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
<voprf::Ristretto255 as Group>::hash_to_curve::<CS>(input, dst)
}
fn hash_to_scalar<CS: voprf::CipherSuite>(
input: &[&[u8]],
dst: &[u8],
) -> voprf::Result<Self::Scalar, voprf::InternalError>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
<voprf::Ristretto255 as Group>::hash_to_scalar::<CS>(input, dst)
}
fn base_elem() -> Self::Elem {
<voprf::Ristretto255 as Group>::base_elem()
}
fn identity_elem() -> Self::Elem {
<voprf::Ristretto255 as Group>::identity_elem()
}
fn serialize_elem(elem: Self::Elem) -> GenericArray<u8, Self::ElemLen> {
<voprf::Ristretto255 as Group>::serialize_elem(elem)
}
fn deserialize_elem(element_bits: &[u8]) -> voprf::Result<Self::Elem> {
<voprf::Ristretto255 as Group>::deserialize_elem(element_bits)
}
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar {
<voprf::Ristretto255 as Group>::random_scalar(rng)
}
fn invert_scalar(scalar: Self::Scalar) -> Self::Scalar {
<voprf::Ristretto255 as Group>::invert_scalar(scalar)
}
fn is_zero_scalar(scalar: Self::Scalar) -> subtle::Choice {
<voprf::Ristretto255 as Group>::is_zero_scalar(scalar)
}
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> {
<voprf::Ristretto255 as Group>::serialize_scalar(scalar)
}
fn deserialize_scalar(scalar_bits: &[u8]) -> voprf::Result<Self::Scalar> {
<voprf::Ristretto255 as Group>::deserialize_scalar(scalar_bits)
}
}
+65 -15
View File
@@ -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<u8, Self::PkLen>) -> Result<Self, InternalError> {
Ok(Self::from(<[u8; 32]>::from(*element_bits)))
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
pk.to_bytes().into()
}
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, Self::SkLen> {
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
if **bytes == [0; 32] {
Err(InternalError::PointError)
} else {
Ok(PublicKey::from(<[_; 32]>::from(*bytes)))
}
}
fn random_sk<R: RngCore + CryptoRng>(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<u8, Self::SkLen>) -> 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<Self::Sk, InternalError>
where
H: Digest + BlockSizeUser,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{
let mut uniform_bytes = GenericArray::<_, U64>::default();
ExpandMsgXmd::<H>::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 to_arr(&self) -> GenericArray<u8, Self::PkLen> {
self.to_bytes().into()
fn public_key(sk: &Self::Sk) -> Self::Pk {
PublicKey::from(sk)
}
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::SkLen> {
StaticSecret::from(<[u8; 32]>::from(*sk))
.diffie_hellman(self)
.to_bytes()
.into()
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
sk.diffie_hellman(pk).to_bytes().into()
}
fn zeroize_sk_on_drop(sk: &mut Self::Sk) {
sk.zeroize()
}
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes().into()
}
fn deserialize_sk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Sk, InternalError> {
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)
}
}
}
}
Executable → Regular
+14 -18
View File
@@ -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
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::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<R: RngCore + CryptoRng>(
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<G>>(
rng: &mut R,
l1_bytes: impl Iterator<Item = &'a [u8]>,
@@ -69,7 +69,7 @@ where
context: &[u8],
) -> Result<GenerateKe2Result<Self, D, G>, ProtocolError<S::Error>>;
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
#[allow(clippy::too_many_arguments)]
fn generate_ke3<'a, 'b, 'c, 'd>(
l2_component: impl Iterator<Item = &'a [u8]>,
ke2_message: Self::KE2Message,
@@ -82,13 +82,10 @@ where
context: &[u8],
) -> Result<GenerateKe3Result<Self, D, G>, ProtocolError>;
#[allow(clippy::type_complexity)]
fn finish_ke(
ke3_message: Self::KE3Message,
ke2_state: &Self::KE2State,
) -> Result<Output<D>, ProtocolError>;
fn ke2_message_size() -> usize;
}
pub trait FromBytes: Sized {
@@ -101,14 +98,13 @@ pub trait ToBytes {
fn to_bytes(&self) -> GenericArray<u8, Self::Len>;
}
#[allow(dead_code)]
pub type Ke1StateLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1State as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1State as ToBytes>::Len;
pub type Ke1MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message as ToBytes>::Len;
pub type Ke2StateLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2State as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2State as ToBytes>::Len;
pub type Ke2MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message as ToBytes>::Len;
pub type Ke3MessageLen<CS: CipherSuite> =
<<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message as ToBytes>::Len;
<<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message as ToBytes>::Len;
Executable → Regular
+120 -31
View File
@@ -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<KG: KeGroup> {
client_e_sk: PrivateKey<KG>,
client_nonce: GenericArray<u8, NonceLen>,
}
impl<KG: KeGroup> Drop for Ke1State<KG> {
fn drop(&mut self) {
self.client_nonce.zeroize();
}
}
impl<KG: KeGroup> ZeroizeOnDrop for Ke1State<KG> {}
/// 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<KG: KeGroup> {
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
pub(crate) client_e_pk: PublicKey<KG>,
}
impl<KG: KeGroup> Drop for Ke1Message<KG> {
fn drop(&mut self) {
self.client_nonce.zeroize();
}
}
impl<KG: KeGroup> ZeroizeOnDrop for Ke1Message<KG> {}
/// 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<D: Hash>
where
D::Core: ProxyHash,
@@ -96,14 +124,41 @@ where
session_key: Output<D>,
}
impl<D: Hash> Drop for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.km3.zeroize();
self.hashed_transcript.zeroize();
self.session_key.zeroize();
}
}
impl<D: Hash> ZeroizeOnDrop for Ke2State<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::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<D: Hash, KG: KeGroup>
where
D::Core: ProxyHash,
@@ -115,13 +170,32 @@ where
mac: Output<D>,
}
impl<D: Hash, KG: KeGroup> Drop for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.server_nonce.zeroize();
self.mac.zeroize();
}
}
impl<D: Hash, KG: KeGroup> ZeroizeOnDrop for Ke2Message<D, KG>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::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<D: Hash>
where
@@ -132,6 +206,25 @@ where
mac: Output<D>,
}
impl<D: Hash> Drop for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.mac.zeroize();
}
}
impl<D: Hash> ZeroizeOnDrop for Ke3Message<D>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::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::<D, KG, S>(
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::<D, KG, PrivateKey<KG>>(
TripleDHComponents {
@@ -322,10 +415,6 @@ where
Ok(ke2_state.session_key.clone())
}
fn ke2_message_size() -> usize {
NonceLen::USIZE + <KG as KeGroup>::PkLen::USIZE + OutputSize::<D>::USIZE
}
}
/////////////////////////
@@ -489,7 +578,7 @@ impl<KG: KeGroup> FromBytes for Ke1State<KG> {
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<KG::SkLen, NonceLen>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
self.client_e_sk.to_arr().concat(self.client_nonce)
self.client_e_sk.serialize().concat(self.client_nonce)
}
}
@@ -521,7 +610,7 @@ impl<KG: KeGroup> FromBytes for Ke1Message<KG> {
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<NonceLen, KG::PkLen>;
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
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::<KG>::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<u8, Self::Len> {
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,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
NonceLen: Add<KG::PkLen>,
Sum<NonceLen, KG::PkLen>: ArrayLength<u8>,
{
fn to_bytes_without_info_or_mac(&self) -> impl Iterator<Item = &[u8]> {
[self.server_nonce.as_slice(), self.server_e_pk.as_slice()].into_iter()
fn to_bytes_without_mac(&self) -> GenericArray<u8, Sum<NonceLen, KG::PkLen>> {
self.server_nonce.concat(self.server_e_pk.to_bytes())
}
}
+74 -162
View File
@@ -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<KG: KeGroup, S: SecretKey<KG> = PrivateKey<KG>> {
pk: PublicKey<KG>,
sk: S,
@@ -51,14 +48,6 @@ impl<KG: KeGroup, S: SecretKey<KG>> KeyPair<KG, S> {
&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<KG>) -> Result<PublicKey<KG>, 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, ProtocolError<S::Error>> {
Self::from_private_key(S::deserialize(input)?)
@@ -77,14 +66,18 @@ impl<KG: KeGroup> KeyPair<KG> {
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<KG: KeGroup> KeyPair<KG> {
impl<KG: KeGroup> KeyPair<KG>
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<Self> {
@@ -104,70 +97,39 @@ impl<KG: KeGroup> KeyPair<KG> {
}
}
/// 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<L: ArrayLength<u8>>(GenericArray<u8, L>);
impl<L: ArrayLength<u8>> Deref for Key<L> {
type Target = GenericArray<u8, L>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// Don't make it implement SizedBytes so that it's not constructible outside of
// this module.
impl<L: ArrayLength<u8>> Key<L> {
/// Convert to bytes
pub fn to_arr(&self) -> GenericArray<u8, L> {
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<KG: KeGroup>(Key<KG::SkLen>);
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)]
pub struct PrivateKey<KG: KeGroup>(KG::Sk);
// This can't be derived because of the use of a generic parameter
impl<KG: KeGroup> Deref for PrivateKey<KG> {
type Target = Key<KG::SkLen>;
fn deref(&self) -> &Self::Target {
&self.0
impl<KG: KeGroup> Drop for PrivateKey<KG> {
fn drop(&mut self) {
KG::zeroize_sk_on_drop(&mut self.0)
}
}
impl<KG: KeGroup> ZeroizeOnDrop for PrivateKey<KG> {}
impl<KG: KeGroup> PrivateKey<KG> {
/// Convert from bytes
pub fn from_arr(key_bytes: GenericArray<u8, KG::SkLen>) -> Self {
PrivateKey(Key(key_bytes))
}
/// Convert from slice
pub fn from_bytes(key_bytes: &[u8]) -> Result<Self, InternalError> {
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<u8, KG::SkLen>) -> Result<Self, InternalError> {
KG::deserialize_sk(key_bytes).map(Self)
}
}
/// A trait specifying the requirements for a private key container
pub trait SecretKey<KG: KeGroup>: Clone + Sized + Zeroize {
pub trait SecretKey<KG: KeGroup>: Clone + Sized {
/// Custom error type that can be passed down to `InternalError::Custom`
type Error;
/// Serialization size in bytes.
@@ -197,20 +159,19 @@ impl<KG: KeGroup> SecretKey<KG> for PrivateKey<KG> {
&self,
pk: PublicKey<KG>,
) -> Result<GenericArray<u8, KG::PkLen>, 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<PublicKey<KG>, InternalError> {
Ok(PublicKey(Key(KG::public_key(&self.0).to_arr())))
Ok(PublicKey(KG::public_key(&self.0)))
}
fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.to_arr()
KG::serialize_sk(&self.0)
}
fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
PrivateKey::from_bytes(input).map_err(InternalError::from)
GenericArray::try_from_slice(input).and_then(Self::from_bytes)
}
}
@@ -218,93 +179,54 @@ impl<KG: KeGroup> SecretKey<KG> for PrivateKey<KG> {
#[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<KG: KeGroup>(Key<KG::PkLen>);
impl<KG: KeGroup> Deref for PublicKey<KG> {
type Target = Key<KG::PkLen>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
pub struct PublicKey<KG: KeGroup>(KG::Pk);
impl<KG: KeGroup> PublicKey<KG> {
/// Convert from bytes
pub fn from_arr(key_bytes: GenericArray<u8, KG::PkLen>) -> Self {
Self(Key(key_bytes))
pub fn from_bytes(key_bytes: &GenericArray<u8, KG::PkLen>) -> Result<Self, InternalError> {
KG::deserialize_pk(key_bytes).map(Self)
}
/// Convert to bytes
pub fn to_bytes(&self) -> GenericArray<u8, KG::PkLen> {
KG::serialize_pk(&self.0)
}
/// Convert from slice
pub fn from_bytes(key_bytes: &[u8]) -> Result<Self, InternalError> {
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<Self, InternalError> {
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<G: KeGroup>() -> Result<(), ProtocolError> {
let key_len = G::PkLen::USIZE;
let mut key = Key::<G::PkLen>(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::<curve25519_dalek::ristretto::RistrettoPoint>()?;
#[cfg(feature = "p256")]
inner::<p256_::PublicKey>()?;
Ok(())
}
#[test]
fn test_zeroize_keypair() {
fn test_zeroize_key() {
fn inner<G: KeGroup>() {
let mut rng = OsRng;
let mut keypair = KeyPair::<G>::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>(G::random_sk(&mut rng));
util::test_zeroize_on_drop(&mut key);
}
#[cfg(feature = "ristretto255")]
inner::<curve25519_dalek::ristretto::RistrettoPoint>();
#[cfg(feature = "p256")]
inner::<p256_::PublicKey>();
inner::<crate::Ristretto255>();
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 = <Default as CipherSuite>::KeGroup;
#[derive(Clone)]
struct RemoteKey(PrivateKey<KeCurve>);
impl SecretKey<KeCurve> 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::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair);
+81 -109
View File
@@ -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<<Default as CipherSuite>::KeGroup>);
//! # #[derive(Clone)]
//! # struct YourRemoteKey(<<Default as CipherSuite>::KeGroup as KeGroup>::Sk);
//! # impl YourRemoteKey {
//! # fn diffie_hellman(&self, pk: &[u8]) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { todo!() }
//! # fn public_key(&self) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(GenericArray::default()) }
//! # fn public_key(&self) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { Ok(<<Default as CipherSuite>::KeGroup>::serialize_pk(&<<Default as CipherSuite>::KeGroup>::public_key(&self.0))) }
//! # }
//! impl SecretKey<<Default as CipherSuite>::KeGroup> for YourRemoteKey {
//! type Error = YourRemoteKeyError;
@@ -985,14 +954,13 @@
//! &self,
//! pk: PublicKey<<Default as CipherSuite>::KeGroup>,
//! ) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, InternalError<Self::Error>> {
//! 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<PublicKey<<Default as CipherSuite>::KeGroup>, InternalError<Self::Error>> {
//! 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<u8, Self::Len> {
@@ -1006,7 +974,7 @@
//! }
//! }
//!
//! # let remote_key = YourRemoteKey(PrivateKey::from_arr(GenericArray::default()));
//! # let remote_key = YourRemoteKey(<<Default as CipherSuite>::KeGroup>::random_sk(&mut OsRng));
//! let keypair = KeyPair::from_private_key(remote_key).unwrap();
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::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,
Executable → Regular
+179 -132
View File
@@ -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<CS::OprfGroup>)]
pub struct RegistrationRequest<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// blinded password information
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
}
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<CS::OprfGroup>, <CS::KeGroup as KeGroup>::Pk)]
pub struct RegistrationResponse<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup, CS::Hash>,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup>,
/// Server's static public key
pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
}
@@ -73,101 +79,133 @@ impl_serialize_and_deserialize_for!(
RegistrationResponse
where
// RegistrationResponse: KgPk + KePk
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
);
/// 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; <CS::KeGroup as KeGroup>::Pk)]
pub struct RegistrationUpload<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// The "envelope" generated by the user, containing sealed cryptographic
/// identifiers
pub(crate) envelope: Envelope<CS>,
/// The masking key used to mask the envelope
pub(crate) masking_key: Output<CS::Hash>,
pub(crate) masking_key: Output<OprfHash<CS>>,
/// The user's public key
pub(crate) client_s_pk: PublicKey<CS::KeGroup>,
}
impl<CS: CipherSuite> Drop for RegistrationUpload<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn drop(&mut self) {
self.masking_key.zeroize();
}
}
impl<CS: CipherSuite> ZeroizeOnDrop for RegistrationUpload<CS>
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
}
impl_serialize_and_deserialize_for!(
RegistrationUpload
where
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
);
/// 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,
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
voprf::BlindedElement<CS::OprfGroup>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
)]
pub struct CredentialRequest<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup, CS::Hash>,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
}
impl_serialize_and_deserialize_for!(
CredentialRequest
where
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
);
/// 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,
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
voprf::EvaluationElement<CS::OprfGroup>,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
)]
pub struct CredentialResponse<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// the server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup, CS::Hash>,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfGroup>,
pub(crate) masking_nonce: GenericArray<u8, NonceLen>,
pub(crate) masked_response: MaskedResponse<CS>,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
pub(crate) ke2_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
}
impl_serialize_and_deserialize_for!(
CredentialResponse
where
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
ArrayLength<u8> | Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>:
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> | Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// 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;
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message,
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message,
)]
pub struct CredentialFinalization<CS: CipherSuite>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message,
pub(crate) ke3_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, 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<CS: CipherSuite> = <CS::OprfGroup as Group>::ElemLen;
pub type RegistrationRequestLen<CS: CipherSuite> = <OprfGroup<CS> as Group>::ElemLen;
impl<CS: CipherSuite> RegistrationRequest<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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<CS::OprfGroup, CS::Hash> {
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
self.blinded_element.clone()
}
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, RegistrationRequestLen<CS>> {
self.blinded_element.value().to_arr()
<OprfGroup<CS> 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<CS: CipherSuite> =
Sum<<CS::OprfGroup as Group>::ElemLen, <CS::KeGroup as KeGroup>::PkLen>;
Sum<<OprfGroup<CS> as Group>::ElemLen, <CS::KeGroup as KeGroup>::PkLen>;
impl<CS: CipherSuite> RegistrationResponse<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
where
// RegistrationResponse: KgPk + KePk
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
{
self.evaluation_element
.value()
.to_arr()
.concat(self.server_s_pk.to_arr())
<OprfGroup<CS> as Group>::serialize_elem(self.evaluation_element.value())
.concat(self.server_s_pk.to_bytes())
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
let elem_len = <OprfGroup<CS> as Group>::ElemLen::USIZE;
let key_len = <CS::KeGroup as KeGroup>::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::<CS::KeGroup>::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: <OprfGroup<CS> 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<CS: CipherSuite> =
Sum<Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>, EnvelopeLen<CS>>;
Sum<Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>, EnvelopeLen<CS>>;
impl<CS: CipherSuite> RegistrationUpload<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, RegistrationUploadLen<CS>>
where
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
{
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<Self, ProtocolError> {
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
let hash_len = OutputSize::<CS::Hash>::USIZE;
let hash_len = OutputSize::<OprfHash<CS>>::USIZE;
let checked_slice =
check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?;
let envelope = Envelope::<CS>::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::<CS::KeGroup>::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<CS, S>,
) -> Self {
let mut masking_key = Output::<CS::Hash>::default();
let mut masking_key = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut masking_key);
Self {
@@ -345,29 +386,30 @@ where
/// Length of [`CredentialRequest`] in bytes for serialization.
pub type CredentialRequestLen<CS: CipherSuite> =
Sum<<CS::OprfGroup as Group>::ElemLen, Ke1MessageLen<CS>>;
Sum<<OprfGroup<CS> as Group>::ElemLen, Ke1MessageLen<CS>>;
impl<CS: CipherSuite> CredentialRequest<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, CredentialRequestLen<CS>>
where
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
{
self.blinded_element
.value()
.to_arr()
<OprfGroup<CS> as Group>::serialize_elem(self.blinded_element.value())
.concat(self.ke1_message.to_bytes())
}
pub(crate) fn serialize_iter<'a>(
blinded_element: &'a GenericArray<u8, <CS::OprfGroup as Group>::ElemLen>,
blinded_element: &'a GenericArray<u8, <OprfGroup<CS> as Group>::ElemLen>,
ke1_message: &'a GenericArray<u8, Ke1MessageLen<CS>>,
) -> impl Iterator<Item = &'a [u8]> {
[blinded_element.as_slice(), ke1_message].into_iter()
@@ -375,23 +417,22 @@ where
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
let elem_len = <OprfGroup<CS> 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::<CS::OprfGroup, CS::Hash>::deserialize(
&checked_slice[..elem_len],
)?;
let blinded_element =
voprf::BlindedElement::<CS::OprfGroup>::deserialize(&checked_slice[..elem_len])?;
// Throw an error if the identity group element is encountered
if blinded_element.value().is_identity() {
if bool::from(<OprfGroup<CS> as Group>::identity_elem().ct_eq(&blinded_element.value())) {
return Err(ProtocolError::IdentityGroupElementError);
}
let ke1_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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<CS::OprfGroup, CS::Hash> {
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
self.blinded_element.clone()
}
}
@@ -415,40 +454,42 @@ pub type CredentialResponseLen<CS: CipherSuite> =
Sum<CredentialResponseWithoutKeLen<CS>, Ke2MessageLen<CS>>;
pub(crate) type CredentialResponseWithoutKeLen<CS: CipherSuite> =
Sum<Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>, MaskedResponseLen<CS>>;
Sum<Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>, MaskedResponseLen<CS>>;
impl<CS: CipherSuite> CredentialResponse<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, CredentialResponseLen<CS>>
where
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
{
self.evaluation_element
.value()
.to_arr()
<OprfGroup<CS> 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<u8, <CS::OprfGroup as Group>::ElemLen>,
beta: &'a GenericArray<u8, <OprfGroup<CS> as Group>::ElemLen>,
masking_nonce: &'a GenericArray<u8, NonceLen>,
masked_response: &'a MaskedResponse<CS>,
) -> impl Iterator<Item = &'a [u8]> {
@@ -459,12 +500,12 @@ where
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
let elem_len = <OprfGroup<CS> as Group>::ElemLen::USIZE;
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
let nonce_len: usize = 32;
let nonce_len = NonceLen::USIZE;
let envelope_len = Envelope::<CS>::len();
let masked_response_len = key_len + envelope_len;
let ke2_message_len = CS::KeyExchange::ke2_message_size();
let ke2_message_len = Ke2MessageLen::<CS>::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::<CS::OprfGroup, CS::Hash>::deserialize(beta_bytes)?;
voprf::EvaluationElement::<CS::OprfGroup>::deserialize(beta_bytes)?;
// Throw an error if the identity group element is encountered
if evaluation_element.value().is_identity() {
if bool::from(<OprfGroup<CS> 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 =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message::from_bytes(
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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: <OprfGroup<CS> 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<CS: CipherSuite> = Ke3MessageLen<CS>;
impl<CS: CipherSuite> CredentialFinalization<CS>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
/// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>> {
@@ -531,7 +576,9 @@ where
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
let ke3_message =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message::from_bytes(input)?;
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::from_bytes(
input,
)?;
Ok(Self { ke3_message })
}
}
Executable → Regular
+310 -261
View File
File diff suppressed because it is too large Load Diff
+15 -1
View File
@@ -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<L: ArrayLength<u8>>(
@@ -157,6 +157,20 @@ impl<T: Mac> MacExt for T {
}
}
pub(crate) trait GenericArrayExt {
fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError>;
}
impl<L: ArrayLength<u8>> GenericArrayExt for GenericArray<u8, L> {
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;
Executable → Regular
+174 -123
View File
@@ -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: CipherSuite>() -> CS::KeGroup
fn random_point<CS: CipherSuite>() -> <CS::KeGroup as KeGroup>::Pk
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// ClientRegistration: KgSk + KgPk
<CS::OprfGroup as Group>::ScalarLen: Add<<CS::OprfGroup as Group>::ElemLen>,
<OprfGroup<CS> as Group>::ScalarLen: Add<<OprfGroup<CS> as Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>,
{
let pw = b"hunter2";
let mut rng = OsRng;
let blind_result =
&voprf::NonVerifiableClient::<CS::OprfGroup, CS::Hash>::blind(pw, &mut rng)?;
let blind_result = &voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
let bytes: Vec<u8> = blind_result
.state
@@ -100,7 +103,6 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
#[cfg(feature = "ristretto255")]
inner::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -110,22 +112,25 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
fn server_registration_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
{
// If we don't have envelope and client_pk, the server registration just
let mut rng = OsRng;
let mut masking_key = Output::<CS::Hash>::default();
let mut masking_key = Output::<OprfHash<CS>>::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::<CS::Hash>::default());
mock_envelope_bytes.extend_from_slice(&Output::<OprfHash<CS>>::default());
let mock_client_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
// serialization order: oprf_key, public key, envelope
let mut bytes = Vec::<u8>::new();
bytes.extend_from_slice(&mock_client_kp.public().to_arr());
bytes.extend_from_slice(&mock_client_kp.public().to_bytes());
bytes.extend_from_slice(&masking_key);
bytes.extend_from_slice(&mock_envelope_bytes);
let reg = ServerRegistration::<CS>::deserialize(&bytes)?;
@@ -151,7 +156,6 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
#[cfg(feature = "ristretto255")]
inner::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -161,12 +165,15 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
fn registration_request_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let pt = random_point::<CS>();
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::<CS>::identity_elem();
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
assert!(matches!(
RegistrationRequest::<CS>::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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -201,18 +207,21 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> {
fn registration_response_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// RegistrationResponse: KgPk + KePk
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
{
let pt = random_point::<CS>();
let beta_bytes = pt.to_arr();
let beta_bytes = CS::KeGroup::serialize_pk(&pt);
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::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::<CS>::identity_elem();
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
assert!(matches!(
RegistrationResponse::<CS>::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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -250,28 +258,31 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
{
let mut rng = OsRng;
let skp = KeyPair::<CS::KeGroup>::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::<CS::Hash>::default();
let mut masking_key = Output::<OprfHash<CS>>::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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -309,22 +319,29 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
fn credential_request_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
{
let mut rng = OsRng;
let alpha = random_point::<CS>();
let alpha_bytes = alpha.to_arr();
let alpha_bytes = CS::KeGroup::serialize_pk(&alpha);
let client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let mut client_nonce = [0u8; NonceLen::USIZE];
rng.fill_bytes(&mut client_nonce);
let ke1m: Vec<u8> = [client_nonce.as_ref(), client_e_kp.public()].concat();
let ke1m: Vec<u8> = [
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::<CS>::identity_elem();
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
assert!(matches!(
CredentialRequest::<CS>::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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -360,24 +376,28 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
fn credential_response_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>,
{
let pt = random_point::<CS>();
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; <CS::OprfGroup as Group>::ElemLen::USIZE + Envelope::<CS>::len()];
vec![0u8; <OprfGroup<CS> as Group>::ElemLen::USIZE + Envelope::<CS>::len()];
rng.fill_bytes(&mut masked_response);
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let mut mac = Output::<CS::Hash>::default();
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let mut server_nonce = [0u8; NonceLen::USIZE];
rng.fill_bytes(&mut server_nonce);
let ke2m: Vec<u8> = [server_nonce.as_ref(), server_e_kp.public(), &mac].concat();
let ke2m: Vec<u8> = [
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::<CS>::identity_elem();
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
assert!(matches!(
CredentialResponse::<CS>::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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -440,12 +464,15 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut rng = OsRng;
let mut mac = Output::<CS::Hash>::default();
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let input = mac;
@@ -459,7 +486,6 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
#[cfg(feature = "ristretto255")]
inner::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -469,15 +495,18 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
fn client_login_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
// ClientLogin: KgSk + CredentialRequest + Ke1State
<CS::OprfGroup as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
Sum<<CS::OprfGroup as Group>::ScalarLen, CredentialRequestLen<CS>>:
<OprfGroup<CS> as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
Sum<<OprfGroup<CS> as Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>,
{
@@ -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::<CS::OprfGroup, CS::Hash>::blind(pw, &mut rng)?;
let blind_result = voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
let credential_request = CredentialRequest::<CS> {
blinded_element: blind_result.message,
ke1_message:
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes(
&[client_nonce.as_ref(), client_e_kp.public()].concat(),
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -531,9 +562,12 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> {
fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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 =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes(&ke1m)?;
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -562,22 +601,32 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut rng = OsRng;
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
let mut mac = Output::<CS::Hash>::default();
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let mut server_nonce = vec![0u8; NonceLen::USIZE];
rng.fill_bytes(&mut server_nonce);
let ke2m: Vec<u8> = [server_nonce.as_slice(), server_e_kp.public(), &mac].concat();
let ke2m: Vec<u8> = [
server_nonce.as_slice(),
server_e_kp.public().to_bytes().as_ref(),
&mac,
]
.concat();
let reg =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message::from_bytes(&ke2m)?;
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -596,18 +644,23 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
fn ke3_message_roundtrip() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
let mut rng = OsRng;
let mut mac = Output::<CS::Hash>::default();
let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac);
let ke3m: Vec<u8> = [mac].concat();
let reg =
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message::from_bytes(&ke3m)?;
<CS::KeyExchange as KeyExchange<OprfHash<CS>, 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::<Ristretto255>()?;
#[cfg(feature = "p256")]
inner::<P256>()?;
Ok(())
@@ -707,5 +759,4 @@ macro_rules! test {
#[cfg(feature = "ristretto255")]
test!(ristretto255, Ristretto255);
#[cfg(feature = "p256")]
test!(p256, P256);
+17 -26
View File
@@ -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<D: Hash>: Default
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
pub trait SlowHash: Default {
/// Computes the slow hashing function
fn hash(&self, input: Output<D>) -> Result<Output<D>, InternalError>;
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError>;
}
/// A no-op hash which simply returns its input
#[derive(Default)]
pub struct NoOpHash;
impl<D: Hash> SlowHash<D> for NoOpHash
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn hash(&self, input: Output<D>) -> Result<Output<D>, InternalError> {
impl SlowHash for NoOpHash {
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> {
Ok(input)
}
}
#[cfg(feature = "slow-hash")]
impl<D: Hash> SlowHash<D> for argon2::Argon2<'_>
where
D::Core: ProxyHash,
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
{
fn hash(&self, input: Output<D>) -> Result<Output<D>, InternalError> {
let mut output = Output::<D>::default();
impl SlowHash for argon2::Argon2<'_> {
fn hash<L: ArrayLength<u8>>(
&self,
input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> {
let mut output = GenericArray::default();
self.hash_password_into(&input, &[0; argon2::MIN_SALT_LEN], &mut output)
.map_err(|_| InternalError::SlowHashError)?;
Ok(output)
Executable → Regular
+355 -277
View File
File diff suppressed because it is too large Load Diff
Executable → Regular
+174 -123
View File
@@ -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<Vec<u8>> {
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<CS: CipherSuite>(values: &JsonValue) -> OpaqueTestVectorParameters
where
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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::<u8, <OprfHash<CS> 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<CS: CipherSuite>(parameters: &OpaqueTestVectorParameters) -> Vec<u8>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// 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_fake_tvs = json_to_test_vectors!(rfc, "Fake", "ristretto255, SHA512",);
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",
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::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_registration_response::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
test_registration_upload::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
@@ -223,37 +246,41 @@ fn tests() -> Result<(), ProtocolError> {
test_fake_vectors::<Ristretto255Sha512NoSlowHash>(&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",);
assert!(
!(p256_real_tvs.is_empty() || p256_fake_tvs.is_empty()),
"Parsing error"
);
struct P256Sha256NoSlowHash;
impl CipherSuite for P256Sha256NoSlowHash {
type OprfGroup = p256_::ProjectivePoint;
type KeGroup = p256_::PublicKey;
type KeyExchange = TripleDH;
type Hash = sha2::Sha256;
type SlowHash = NoOpHash;
}
test_registration_request::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_response::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_upload::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke1::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke2::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke3::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_server_login_finish::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_fake_vectors::<P256Sha256NoSlowHash>(&p256_fake_tvs)?;
struct P256Sha256NoSlowHash;
impl CipherSuite for P256Sha256NoSlowHash {
type OprfGroup = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = TripleDH;
type SlowHash = NoOpHash;
}
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
);
assert!(
!(p256_real_tvs.is_empty() || p256_fake_tvs.is_empty()),
"Parsing error"
);
test_registration_request::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_response::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_registration_upload::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke1::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke2::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_ke3::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_server_login_finish::<P256Sha256NoSlowHash>(&p256_real_tvs)?;
test_fake_vectors::<P256Sha256NoSlowHash>(&p256_fake_tvs)?;
Ok(())
}
@@ -261,9 +288,12 @@ fn test_registration_request<CS: CipherSuite>(
tvs: &[OpaqueTestVectorParameters],
) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> 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<CS: CipherSuite>(
tvs: &[OpaqueTestVectorParameters],
) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// RegistrationResponse: KgPk + KePk
<CS::OprfGroup as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
<OprfGroup<CS> as Group>::ElemLen: Add<<CS::KeGroup as KeGroup>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>,
{
for parameters in tvs {
@@ -318,15 +351,18 @@ fn test_registration_upload<CS: CipherSuite>(
tvs: &[OpaqueTestVectorParameters],
) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
{
@@ -362,7 +398,7 @@ where
);
assert_eq!(
hex::encode(&parameters.export_key),
hex::encode(result.export_key.to_vec())
hex::encode(result.export_key)
);
}
@@ -371,11 +407,14 @@ where
fn test_ke1<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// CredentialRequest: KgPk + Ke1Message
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>,
{
for parameters in tvs {
@@ -404,29 +443,32 @@ where
fn test_ke2<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
@@ -489,12 +531,15 @@ where
fn test_ke3<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
for parameters in tvs {
@@ -549,21 +594,24 @@ fn test_server_login_finish<CS: CipherSuite>(
tvs: &[OpaqueTestVectorParameters],
) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash
NonceLen: Add<OutputSize<CS::Hash>>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
EnvelopeLen<CS>: ArrayLength<u8>,
// RegistrationUpload: (KePk + Hash) + Envelope
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>,
// ServerRegistration = RegistrationUpload
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
{
for parameters in tvs {
@@ -618,16 +666,19 @@ fn test_fake_vectors<CS: CipherSuite>(
tvs: &[OpaqueTestVectorParameters],
) -> Result<(), ProtocolError>
where
<CS::Hash as CoreProxy>::Core: ProxyHash,
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
<OprfHash<CS> as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
OprfHash<CS>: Hash,
<OprfHash<CS> as CoreProxy>::Core: ProxyHash,
<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<OprfHash<CS> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
// MaskedResponse: (Nonce + Hash) + KePk
NonceLen: Add<OutputSize<CS::Hash>>,
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
NonceLen: Add<OutputSize<OprfHash<CS>>>,
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
MaskedResponseLen<CS>: ArrayLength<u8>,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
+41
View File
@@ -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<T: Sized>(value: &mut T) {
drop_manually(value);
test_zeroized(value);
}
#[cfg(test)]
pub(crate) fn test_zeroized<T: Sized>(value: &mut T) {
use std::{mem, slice, vec};
let test =
unsafe { slice::from_raw_parts(value as *const _ as *const u8, mem::size_of::<T>()) };
assert_eq!(test, vec![0; mem::size_of::<T>()]);
}
#[cfg(test)]
pub(crate) fn drop_manually<T: Sized>(value: &mut T) {
use std::{mem, ptr, vec};
assert!(mem::needs_drop::<T>());
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);
}