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:
+42
-51
@@ -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
@@ -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" }
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
+14
-11
@@ -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
@@ -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
@@ -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
@@ -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>;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
Executable → Regular
+174
-123
@@ -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(¶meters.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
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user