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
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- ristretto255_u64
|
- --features ristretto255_u64,ristretto255_voprf
|
||||||
- ristretto255_u32
|
- --features ristretto255_u32,ristretto255_voprf
|
||||||
- p256
|
-
|
||||||
- x25519_u64,ristretto255_u64
|
- --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:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.56.1
|
- 1.57.0
|
||||||
name: test
|
name: test
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
@@ -36,13 +43,13 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
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
|
- name: Run cargo test with std
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
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:
|
cross-test:
|
||||||
name: Test on ${{ matrix.target }} (using cross)
|
name: Test on ${{ matrix.target }} (using cross)
|
||||||
@@ -54,43 +61,21 @@ jobs:
|
|||||||
# 32-bit x86
|
# 32-bit x86
|
||||||
- i686-unknown-linux-gnu
|
- i686-unknown-linux-gnu
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- ristretto255_u64
|
- --features ristretto255_u64,ristretto255_voprf
|
||||||
- ristretto255_u32
|
- --features ristretto255_u32,ristretto255_voprf
|
||||||
- p256
|
-
|
||||||
- x25519_u64,ristretto255_u64
|
- x25519_u64,ristretto255_u64,ristretto255_voprf
|
||||||
|
- x25519_u32,ristretto255_u64,ristretto255_voprf
|
||||||
|
- x25519_u64
|
||||||
|
- x25519_u32
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: hecrj/setup-rust-action@v1
|
- uses: hecrj/setup-rust-action@v1
|
||||||
- run: cargo install cross
|
- run: cargo install cross
|
||||||
# Note: just use `cross` as you would `cargo`, but always
|
# Note: just use `cross` as you would `cargo`, but always
|
||||||
# pass the `--target=${{ matrix.target }}` arg. (Yes, really).
|
# 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 ${{ matrix.backend_feature }}
|
||||||
- run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features std --features ${{ matrix.backend_feature }}
|
- run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features std ${{ 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 }}
|
|
||||||
|
|
||||||
simple-login-test:
|
simple-login-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -99,7 +84,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.56.1
|
- 1.57.0
|
||||||
name: test simple_login command-line example
|
name: test simple_login command-line example
|
||||||
steps:
|
steps:
|
||||||
- name: install expect
|
- name: install expect
|
||||||
@@ -122,7 +107,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.56.1
|
- 1.57.0
|
||||||
name: test digital_locker command-line example
|
name: test digital_locker command-line example
|
||||||
steps:
|
steps:
|
||||||
- name: install expect
|
- name: install expect
|
||||||
@@ -150,10 +135,13 @@ jobs:
|
|||||||
# for any no_std target
|
# for any no_std target
|
||||||
- thumbv6m-none-eabi
|
- thumbv6m-none-eabi
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- ristretto255_u64
|
- ristretto255_u64,ristretto255_voprf
|
||||||
- ristretto255_u32
|
- ristretto255_u32,ristretto255_voprf
|
||||||
- p256
|
-
|
||||||
- x25519_u64,ristretto255_u64
|
- x25519_u64,ristretto255_u64,ristretto255_voprf
|
||||||
|
- x25519_u32,ristretto255_u32,ristretto255_voprf
|
||||||
|
- x25519_u64
|
||||||
|
- x25519_u32
|
||||||
frontend_feature:
|
frontend_feature:
|
||||||
- slow-hash
|
- slow-hash
|
||||||
- serde
|
- serde
|
||||||
@@ -170,10 +158,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- ristretto255_u64
|
- --features ristretto255_u64,ristretto255_voprf
|
||||||
- ristretto255_u32
|
- --features ristretto255_u32,ristretto255_voprf
|
||||||
- p256
|
-
|
||||||
- x25519_u64,ristretto255_u64
|
- --features x25519_u64,ristretto255_u64,ristretto255_voprf
|
||||||
|
- --features x25519_u32,ristretto255_u32,ristretto255_voprf
|
||||||
|
- --features x25519_u32
|
||||||
|
- --features x25519_u32
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -189,7 +180,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: bench
|
command: bench
|
||||||
args: --no-default-features --features ${{ matrix.backend_feature }} --no-run
|
args: --no-default-features ${{ matrix.backend_feature }} --no-run
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
name: cargo clippy
|
name: cargo clippy
|
||||||
@@ -210,7 +201,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --all-targets -- -D warnings
|
args: --all-targets --features slow-hash,std,x25519_u64 -- -D warnings
|
||||||
|
|
||||||
- name: Run cargo doc
|
- name: Run cargo doc
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
@@ -218,7 +209,7 @@ jobs:
|
|||||||
RUSTDOCFLAGS: -D warnings
|
RUSTDOCFLAGS: -D warnings
|
||||||
with:
|
with:
|
||||||
command: doc
|
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:
|
format:
|
||||||
name: cargo fmt
|
name: cargo fmt
|
||||||
|
|||||||
Executable → Regular
+33
-40
@@ -8,47 +8,27 @@ license = "Apache-2.0 OR MIT"
|
|||||||
name = "opaque-ke"
|
name = "opaque-ke"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/novifinancial/opaque-ke"
|
repository = "https://github.com/novifinancial/opaque-ke"
|
||||||
rust-version = "1.56"
|
rust-version = "1.57"
|
||||||
version = "2.0.0-pre.1"
|
version = "2.0.0-pre.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ristretto255_u64", "serde"]
|
default = ["ristretto255_u64", "ristretto255_voprf", "serde"]
|
||||||
p256 = ["p256_", "voprf/p256"]
|
ristretto255 = ["curve25519-dalek", "voprf/ristretto255"]
|
||||||
ristretto255 = []
|
ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"]
|
||||||
ristretto255_fiat_u32 = [
|
ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"]
|
||||||
"curve25519-dalek/fiat_u32_backend",
|
ristretto255_simd = ["curve25519-dalek/simd_backend", "ristretto255"]
|
||||||
"ristretto255",
|
ristretto255_u32 = ["curve25519-dalek/u32_backend", "ristretto255"]
|
||||||
"voprf/ristretto255_fiat_u32",
|
ristretto255_u64 = ["curve25519-dalek/u64_backend", "ristretto255"]
|
||||||
]
|
ristretto255_voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"]
|
||||||
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",
|
|
||||||
]
|
|
||||||
serde = ["serde_", "generic-array/serde", "voprf/serde"]
|
serde = ["serde_", "generic-array/serde", "voprf/serde"]
|
||||||
slow-hash = ["argon2"]
|
slow-hash = ["argon2"]
|
||||||
std = ["getrandom", "rand/std", "rand/std_rng", "voprf/std"]
|
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_u32 = ["x25519", "x25519-dalek/fiat_u32_backend"]
|
||||||
x25519_fiat_u64 = ["x25519", "x25519-dalek/fiat_u64_backend"]
|
x25519_fiat_u64 = ["x25519", "x25519-dalek/fiat_u64_backend"]
|
||||||
# x25519-dalek isn't properly re-exposing `simd_backend`.
|
# x25519-dalek isn't properly re-exposing `simd_backend`.
|
||||||
x25519_simd = [
|
x25519_simd = [
|
||||||
"curve25519-dalek/simd_backend",
|
"curve25519-dalek-3/simd_backend",
|
||||||
"x25519",
|
"x25519",
|
||||||
"x25519-dalek/nightly",
|
"x25519-dalek/nightly",
|
||||||
]
|
]
|
||||||
@@ -60,26 +40,23 @@ argon2 = { version = "0.3", default-features = false, features = [
|
|||||||
"alloc",
|
"alloc",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
constant_time_eq = "0.1"
|
constant_time_eq = "0.1"
|
||||||
curve25519-dalek = { version = "3", default-features = false, optional = true }
|
curve25519-dalek = { version = "=4.0.0-pre.1", default-features = false, optional = true }
|
||||||
derive-where = { version = "1.0.0-rc.1", features = ["zeroize"] }
|
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"
|
digest = "0.10"
|
||||||
displaydoc = { version = "0.2", default-features = false }
|
displaydoc = { version = "0.2", default-features = false }
|
||||||
|
elliptic-curve = { version = "0.12.0-pre.1", features = ["hash2curve", "sec1"] }
|
||||||
generic-array = "0.14"
|
generic-array = "0.14"
|
||||||
getrandom = { version = "0.2", optional = true }
|
getrandom = { version = "0.2", optional = true }
|
||||||
hkdf = "0.12"
|
hkdf = "0.12"
|
||||||
hmac = "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 }
|
rand = { version = "0.8", default-features = false }
|
||||||
serde_ = { version = "1", package = "serde", default-features = false, features = [
|
serde_ = { version = "1", package = "serde", default-features = false, features = [
|
||||||
"derive",
|
"derive",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
subtle = { version = "2.3", default-features = false }
|
subtle = { version = "2.3", default-features = false }
|
||||||
voprf = { git = "https://github.com/novifinancial/voprf", rev = "55ef981a3f9a12eddd8c372ffdf51818011343ee", default-features = false, features = [
|
voprf = { version = "0.3", default-features = false, features = ["danger"] }
|
||||||
"danger",
|
x25519-dalek = { version = "=2.0.0-pre.1", default-features = false, optional = true }
|
||||||
] }
|
|
||||||
x25519-dalek = { version = "1", default-features = false, optional = true }
|
|
||||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
@@ -93,7 +70,12 @@ criterion = "0.3"
|
|||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
json = "0.12"
|
json = "0.12"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
|
p256 = { version = "=0.11.0-pre.0", default-features = false, features = [
|
||||||
|
"hash2curve",
|
||||||
|
"voprf",
|
||||||
|
] }
|
||||||
proptest = "1"
|
proptest = "1"
|
||||||
|
rand = "0.8"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
rustyline = "9"
|
rustyline = "9"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
@@ -102,3 +84,14 @@ sha2 = "0.10"
|
|||||||
[[bench]]
|
[[bench]]
|
||||||
harness = false
|
harness = false
|
||||||
name = "opaque"
|
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
|
### Minimum Supported Rust Version
|
||||||
|
|
||||||
Rust **1.56** or higher.
|
Rust **1.57** or higher.
|
||||||
|
|
||||||
Audit
|
Audit
|
||||||
-----
|
-----
|
||||||
|
|||||||
+5
-7
@@ -20,26 +20,24 @@ static SUFFIX: &str = "ristretto255_u32";
|
|||||||
static SUFFIX: &str = "ristretto255_fiat_u64";
|
static SUFFIX: &str = "ristretto255_fiat_u64";
|
||||||
#[cfg(feature = "ristretto255_fiat_u32")]
|
#[cfg(feature = "ristretto255_fiat_u32")]
|
||||||
static SUFFIX: &str = "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";
|
static SUFFIX: &str = "p256";
|
||||||
|
|
||||||
struct Default;
|
struct Default;
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type OprfGroup = opaque_ke::Ristretto255;
|
||||||
type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type KeGroup = opaque_ke::Ristretto255;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha512;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = p256_::ProjectivePoint;
|
type OprfGroup = p256::NistP256;
|
||||||
type KeGroup = p256_::PublicKey;
|
type KeGroup = p256::NistP256;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha256;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,19 +49,17 @@ struct Default;
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type OprfGroup = opaque_ke::Ristretto255;
|
||||||
type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type KeGroup = opaque_ke::Ristretto255;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha512;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = p256_::ProjectivePoint;
|
type OprfGroup = p256::NistP256;
|
||||||
type KeGroup = p256_::PublicKey;
|
type KeGroup = p256::NistP256;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha256;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,19 +43,17 @@ struct Default;
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type OprfGroup = opaque_ke::Ristretto255;
|
||||||
type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type KeGroup = opaque_ke::Ristretto255;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha512;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
type OprfGroup = p256_::ProjectivePoint;
|
type OprfGroup = p256::NistP256;
|
||||||
type KeGroup = p256_::PublicKey;
|
type KeGroup = p256::NistP256;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
type Hash = sha2::Sha256;
|
|
||||||
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Executable → Regular
+14
-11
@@ -9,8 +9,8 @@
|
|||||||
//! OPAQUE
|
//! OPAQUE
|
||||||
|
|
||||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||||
use generic_array::typenum::{IsLess, Le, NonZero, U256};
|
use digest::OutputSizeUser;
|
||||||
use voprf::Group as OprfGroup;
|
use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, U256};
|
||||||
|
|
||||||
use crate::hash::{Hash, ProxyHash};
|
use crate::hash::{Hash, ProxyHash};
|
||||||
use crate::key_exchange::group::KeGroup;
|
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
|
/// * `SlowHash`: A slow hashing function, typically used for password hashing
|
||||||
pub trait CipherSuite
|
pub trait CipherSuite
|
||||||
where
|
where
|
||||||
<Self::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<Self> as OutputSizeUser>::OutputSize:
|
||||||
<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<Self> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// A finite cyclic group along with a point representation along with an
|
||||||
/// extension trait PasswordToCurve that allows some customization on how to
|
/// extension trait PasswordToCurve that allows some customization on how to
|
||||||
/// hash a password to a curve point. See `group::Group`.
|
/// hash a password to a curve point. See `group::Group`.
|
||||||
type OprfGroup: OprfGroup;
|
type OprfGroup: voprf::CipherSuite;
|
||||||
/// A `Group` used for the `KeyExchange`.
|
/// A `Group` used for the `KeyExchange`.
|
||||||
type KeGroup: KeGroup;
|
type KeGroup: KeGroup;
|
||||||
/// A key exchange protocol
|
/// A key exchange protocol
|
||||||
type KeyExchange: KeyExchange<Self::Hash, Self::KeGroup>;
|
type KeyExchange: KeyExchange<OprfHash<Self>, Self::KeGroup>;
|
||||||
/// The main hash function use (for HKDF computations and hashing
|
|
||||||
/// transcripts)
|
|
||||||
type Hash: Hash;
|
|
||||||
/// A slow hashing function, typically used for password hashing
|
/// 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::convert::TryFrom;
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
|
||||||
use derive_where::DeriveWhere;
|
use derive_where::derive_where;
|
||||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||||
use digest::Output;
|
use digest::{Output, OutputSizeUser};
|
||||||
use generic_array::sequence::Concat;
|
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 generic_array::{ArrayLength, GenericArray};
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use voprf::Group;
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
use zeroize::Zeroize;
|
|
||||||
|
|
||||||
use crate::ciphersuite::CipherSuite;
|
use crate::ciphersuite::{CipherSuite, OprfHash};
|
||||||
use crate::errors::utils::check_slice_size;
|
use crate::errors::utils::check_slice_size;
|
||||||
use crate::errors::{InternalError, ProtocolError};
|
use crate::errors::{InternalError, ProtocolError};
|
||||||
use crate::hash::{Hash, OutputSize, ProxyHash};
|
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";
|
const STR_OPAQUE_DERIVE_AUTH_KEY_PAIR: [u8; 24] = *b"OPAQUE-DeriveAuthKeyPair";
|
||||||
type NonceLen = U32;
|
type NonceLen = U32;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
|
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)]
|
||||||
#[zeroize(drop)]
|
|
||||||
pub(crate) enum InnerEnvelopeMode {
|
pub(crate) enum InnerEnvelopeMode {
|
||||||
Zero = 0,
|
Zero = 0,
|
||||||
Internal = 1,
|
Internal = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Zeroize for InnerEnvelopeMode {
|
||||||
|
fn zeroize(&mut self) {
|
||||||
|
*self = Self::Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for InnerEnvelopeMode {
|
impl TryFrom<u8> for InnerEnvelopeMode {
|
||||||
type Error = ProtocolError;
|
type Error = ProtocolError;
|
||||||
fn try_from(x: u8) -> Result<Self, Self::Error> {
|
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
|
/// The specification update has simplified this assumption by taking an
|
||||||
/// XOR-based approach without compromising on security, and to avoid the
|
/// XOR-based approach without compromising on security, and to avoid the
|
||||||
/// confusion around the implementation of an RKR-secure encryption.
|
/// confusion around the implementation of an RKR-secure encryption.
|
||||||
#[derive(DeriveWhere)]
|
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
|
||||||
pub(crate) struct Envelope<CS: CipherSuite>
|
pub(crate) struct Envelope<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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>,
|
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
|
// Note that this struct represents an envelope that has been "opened" with the
|
||||||
@@ -80,12 +113,15 @@ where
|
|||||||
// contents.
|
// contents.
|
||||||
pub(crate) struct OpenedEnvelope<'a, CS: CipherSuite>
|
pub(crate) struct OpenedEnvelope<'a, CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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) 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_u: Serialize<'a, U2, <CS::KeGroup as KeGroup>::PkLen>,
|
||||||
pub(crate) id_s: 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))]
|
#[cfg(not(test))]
|
||||||
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<CS::Hash>);
|
type SealRawResult<CS: CipherSuite> = (Envelope<CS>, Output<OprfHash<CS>>);
|
||||||
#[cfg(test)]
|
#[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))]
|
#[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)]
|
#[cfg(test)]
|
||||||
type SealResult<CS: CipherSuite> = (
|
type SealResult<CS: CipherSuite> = (
|
||||||
Envelope<CS>,
|
Envelope<CS>,
|
||||||
PublicKey<CS::KeGroup>,
|
PublicKey<CS::KeGroup>,
|
||||||
Output<CS::Hash>,
|
Output<OprfHash<CS>>,
|
||||||
Output<CS::Hash>,
|
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>
|
impl<CS: CipherSuite> Envelope<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) fn seal<R: RngCore + CryptoRng>(
|
pub(crate) fn seal<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
server_s_pk: &PublicKey<CS::KeGroup>,
|
server_s_pk: &PublicKey<CS::KeGroup>,
|
||||||
ids: Identifiers,
|
ids: Identifiers,
|
||||||
) -> Result<SealResult<CS>, ProtocolError> {
|
) -> Result<SealResult<CS>, ProtocolError> {
|
||||||
@@ -136,12 +175,13 @@ where
|
|||||||
build_inner_envelope_internal::<CS>(randomized_pwd_hasher.clone(), nonce)?,
|
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>(
|
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
|
||||||
ids,
|
ids,
|
||||||
client_s_pk.to_arr(),
|
client_s_pk.to_bytes(),
|
||||||
server_s_pk.to_arr(),
|
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)?;
|
let result = Self::seal_raw(randomized_pwd_hasher, nonce, aad, mode)?;
|
||||||
Ok((
|
Ok((
|
||||||
@@ -157,13 +197,13 @@ where
|
|||||||
/// the aad field. Note that a new nonce is sampled for each call to seal.
|
/// the aad field. Note that a new nonce is sampled for each call to seal.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) fn seal_raw<'a>(
|
pub(crate) fn seal_raw<'a>(
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
nonce: GenericArray<u8, NonceLen>,
|
nonce: GenericArray<u8, NonceLen>,
|
||||||
aad: impl Iterator<Item = &'a [u8]>,
|
aad: impl Iterator<Item = &'a [u8]>,
|
||||||
mode: InnerEnvelopeMode,
|
mode: InnerEnvelopeMode,
|
||||||
) -> Result<SealRawResult<CS>, InternalError> {
|
) -> Result<SealRawResult<CS>, InternalError> {
|
||||||
let mut hmac_key = Output::<CS::Hash>::default();
|
let mut hmac_key = Output::<OprfHash<CS>>::default();
|
||||||
let mut export_key = Output::<CS::Hash>::default();
|
let mut export_key = Output::<OprfHash<CS>>::default();
|
||||||
|
|
||||||
randomized_pwd_hasher
|
randomized_pwd_hasher
|
||||||
.expand_multi_info(&[&nonce, &STR_AUTH_KEY], &mut hmac_key)
|
.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)
|
.expand_multi_info(&[&nonce, &STR_EXPORT_KEY], &mut export_key)
|
||||||
.map_err(|_| InternalError::HkdfError)?;
|
.map_err(|_| InternalError::HkdfError)?;
|
||||||
|
|
||||||
let mut hmac =
|
let mut hmac = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
|
||||||
Hmac::<CS::Hash>::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?;
|
.map_err(|_| InternalError::HmacError)?;
|
||||||
hmac.update(&nonce);
|
hmac.update(&nonce);
|
||||||
hmac.update_iter(aad);
|
hmac.update_iter(aad);
|
||||||
|
|
||||||
@@ -193,7 +233,7 @@ where
|
|||||||
|
|
||||||
pub(crate) fn open<'a>(
|
pub(crate) fn open<'a>(
|
||||||
&self,
|
&self,
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
server_s_pk: PublicKey<CS::KeGroup>,
|
server_s_pk: PublicKey<CS::KeGroup>,
|
||||||
optional_ids: Identifiers<'a>,
|
optional_ids: Identifiers<'a>,
|
||||||
) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> {
|
) -> 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>(
|
let (id_u, id_s) = bytestrings_from_identifiers::<CS::KeGroup>(
|
||||||
optional_ids,
|
optional_ids,
|
||||||
client_static_keypair.public().to_arr(),
|
client_static_keypair.public().to_bytes(),
|
||||||
server_s_pk.to_arr(),
|
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)?;
|
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.
|
/// if the key and aad used to construct the envelope are the same.
|
||||||
pub(crate) fn open_raw<'a>(
|
pub(crate) fn open_raw<'a>(
|
||||||
&self,
|
&self,
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
aad: impl Iterator<Item = &'a [u8]>,
|
aad: impl Iterator<Item = &'a [u8]>,
|
||||||
) -> Result<OpenedInnerEnvelope<CS::Hash>, InternalError> {
|
) -> Result<OpenedInnerEnvelope<OprfHash<CS>>, InternalError> {
|
||||||
let mut hmac_key = Output::<CS::Hash>::default();
|
let mut hmac_key = Output::<OprfHash<CS>>::default();
|
||||||
let mut export_key = Output::<CS::Hash>::default();
|
let mut export_key = Output::<OprfHash<CS>>::default();
|
||||||
|
|
||||||
randomized_pwd_hasher
|
randomized_pwd_hasher
|
||||||
.expand(&self.nonce.concat(STR_AUTH_KEY.into()), &mut hmac_key)
|
.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)
|
.expand(&self.nonce.concat(STR_EXPORT_KEY.into()), &mut export_key)
|
||||||
.map_err(|_| InternalError::HkdfError)?;
|
.map_err(|_| InternalError::HkdfError)?;
|
||||||
|
|
||||||
let mut hmac =
|
let mut hmac = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
|
||||||
Hmac::<CS::Hash>::new_from_slice(&hmac_key).map_err(|_| InternalError::HmacError)?;
|
.map_err(|_| InternalError::HmacError)?;
|
||||||
hmac.update(&self.nonce);
|
hmac.update(&self.nonce);
|
||||||
hmac.update_iter(aad);
|
hmac.update_iter(aad);
|
||||||
hmac.verify(&self.hmac)
|
hmac.verify(&self.hmac)
|
||||||
@@ -260,17 +301,17 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn hmac_key_size() -> usize {
|
fn hmac_key_size() -> usize {
|
||||||
OutputSize::<CS::Hash>::USIZE
|
OutputSize::<OprfHash<CS>>::USIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn len() -> 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>>
|
pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>>
|
||||||
where
|
where
|
||||||
// Envelope: Nonce + Hash
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
self.nonce.concat(self.hmac.clone())
|
self.nonce.concat(self.hmac.clone())
|
||||||
@@ -305,22 +346,25 @@ where
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
|
|
||||||
fn build_inner_envelope_internal<CS: CipherSuite>(
|
fn build_inner_envelope_internal<CS: CipherSuite>(
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
nonce: GenericArray<u8, NonceLen>,
|
nonce: GenericArray<u8, NonceLen>,
|
||||||
) -> Result<PublicKey<CS::KeGroup>, ProtocolError>
|
) -> Result<PublicKey<CS::KeGroup>, ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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();
|
let mut keypair_seed = GenericArray::<_, <CS::KeGroup as KeGroup>::SkLen>::default();
|
||||||
randomized_pwd_hasher
|
randomized_pwd_hasher
|
||||||
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
|
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
|
||||||
.map_err(|_| InternalError::HkdfError)?;
|
.map_err(|_| InternalError::HkdfError)?;
|
||||||
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
|
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
|
||||||
&CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash, _, _>(
|
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
|
||||||
[keypair_seed.as_slice()],
|
&[keypair_seed.as_slice()],
|
||||||
GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
|
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
|
||||||
)?),
|
)?),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -328,22 +372,25 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn recover_keys_internal<CS: CipherSuite>(
|
fn recover_keys_internal<CS: CipherSuite>(
|
||||||
randomized_pwd_hasher: Hkdf<CS::Hash>,
|
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||||
nonce: GenericArray<u8, NonceLen>,
|
nonce: GenericArray<u8, NonceLen>,
|
||||||
) -> Result<KeyPair<CS::KeGroup>, ProtocolError>
|
) -> Result<KeyPair<CS::KeGroup>, ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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();
|
let mut keypair_seed = GenericArray::<_, <CS::KeGroup as KeGroup>::SkLen>::default();
|
||||||
randomized_pwd_hasher
|
randomized_pwd_hasher
|
||||||
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
|
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed)
|
||||||
.map_err(|_| InternalError::HkdfError)?;
|
.map_err(|_| InternalError::HkdfError)?;
|
||||||
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
|
let client_static_keypair = KeyPair::<CS::KeGroup>::from_private_key_slice(
|
||||||
&CS::OprfGroup::scalar_as_bytes(CS::OprfGroup::hash_to_scalar::<CS::Hash, _, _>(
|
&CS::KeGroup::serialize_sk(&CS::KeGroup::hash_to_scalar::<OprfHash<CS>>(
|
||||||
[keypair_seed.as_slice()],
|
&[keypair_seed.as_slice()],
|
||||||
GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
|
&GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR),
|
||||||
)?),
|
)?),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
+16
-12
@@ -31,8 +31,8 @@ pub enum InternalError<T = Infallible> {
|
|||||||
},
|
},
|
||||||
/// Could not decompress point.
|
/// Could not decompress point.
|
||||||
PointError,
|
PointError,
|
||||||
/// Computing the hash-to-curve function failed
|
/// Size of input is empty or longer then [`u16::MAX`].
|
||||||
HashToCurveError,
|
HashToScalar,
|
||||||
/// Computing HKDF failed while deriving subkeys
|
/// Computing HKDF failed while deriving subkeys
|
||||||
HkdfError,
|
HkdfError,
|
||||||
/// Computing HMAC failed while supplying a secret key
|
/// 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
|
/** This error occurs when attempting to open an envelope of the wrong
|
||||||
type (base mode, custom identifier) */
|
type (base mode, custom identifier) */
|
||||||
IncompatibleEnvelopeModeError,
|
IncompatibleEnvelopeModeError,
|
||||||
/// This error occurs when the inner envelope is malformed
|
|
||||||
InvalidInnerEnvelopeError,
|
|
||||||
/// Error from the OPRF evaluation
|
/// Error from the OPRF evaluation
|
||||||
OprfError(voprf::Error),
|
OprfError(voprf::Error),
|
||||||
/// Error encountered when attempting to produce a keypair
|
/// Error from the OPRF evaluation
|
||||||
InvalidKeypairError,
|
OprfInternalError(voprf::InternalError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for InternalError<T> {
|
impl<T: Debug> Debug for InternalError<T> {
|
||||||
@@ -69,7 +67,7 @@ impl<T: Debug> Debug for InternalError<T> {
|
|||||||
.field("actual_len", actual_len)
|
.field("actual_len", actual_len)
|
||||||
.finish(),
|
.finish(),
|
||||||
Self::PointError => f.debug_tuple("PointError").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::HkdfError => f.debug_tuple("HkdfError").finish(),
|
||||||
Self::HmacError => f.debug_tuple("HmacError").finish(),
|
Self::HmacError => f.debug_tuple("HmacError").finish(),
|
||||||
Self::SlowHashError => f.debug_tuple("SlowHashError").finish(),
|
Self::SlowHashError => f.debug_tuple("SlowHashError").finish(),
|
||||||
@@ -77,9 +75,10 @@ impl<T: Debug> Debug for InternalError<T> {
|
|||||||
Self::IncompatibleEnvelopeModeError => {
|
Self::IncompatibleEnvelopeModeError => {
|
||||||
f.debug_tuple("IncompatibleEnvelopeModeError").finish()
|
f.debug_tuple("IncompatibleEnvelopeModeError").finish()
|
||||||
}
|
}
|
||||||
Self::InvalidInnerEnvelopeError => f.debug_tuple("InvalidInnerEnvelopeError").finish(),
|
|
||||||
Self::OprfError(error) => f.debug_tuple("OprfError").field(error).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,
|
actual_len,
|
||||||
},
|
},
|
||||||
Self::PointError => InternalError::PointError,
|
Self::PointError => InternalError::PointError,
|
||||||
Self::HashToCurveError => InternalError::HashToCurveError,
|
Self::HashToScalar => InternalError::HashToScalar,
|
||||||
Self::HkdfError => InternalError::HkdfError,
|
Self::HkdfError => InternalError::HkdfError,
|
||||||
Self::HmacError => InternalError::HmacError,
|
Self::HmacError => InternalError::HmacError,
|
||||||
Self::SlowHashError => InternalError::SlowHashError,
|
Self::SlowHashError => InternalError::SlowHashError,
|
||||||
Self::SealOpenHmacError => InternalError::SealOpenHmacError,
|
Self::SealOpenHmacError => InternalError::SealOpenHmacError,
|
||||||
Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError,
|
Self::IncompatibleEnvelopeModeError => InternalError::IncompatibleEnvelopeModeError,
|
||||||
Self::InvalidInnerEnvelopeError => InternalError::InvalidInnerEnvelopeError,
|
|
||||||
Self::OprfError(error) => InternalError::OprfError(error),
|
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
|
/// Represents an error in protocol handling
|
||||||
#[derive(Clone, Copy, Display, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Display, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub enum ProtocolError<T = Infallible> {
|
pub enum ProtocolError<T = Infallible> {
|
||||||
|
|||||||
Executable → Regular
+24
-12
@@ -11,9 +11,12 @@ macro_rules! impl_serialize_and_deserialize_for {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<CS: CipherSuite> serde_::Serialize for $item<CS>
|
impl<CS: CipherSuite> serde_::Serialize for $item<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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)*),+)?
|
$($($path: $bound1 $(+ $bound2)*),+)?
|
||||||
{
|
{
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
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")]
|
#[cfg(feature = "serde")]
|
||||||
impl<'de, CS: CipherSuite> serde_::Deserialize<'de> for $item<CS>
|
impl<'de, CS: CipherSuite> serde_::Deserialize<'de> for $item<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@@ -39,15 +45,21 @@ macro_rules! impl_serialize_and_deserialize_for {
|
|||||||
|
|
||||||
struct ByteVisitor<CS: CipherSuite>(core::marker::PhantomData<CS>)
|
struct ByteVisitor<CS: CipherSuite>(core::marker::PhantomData<CS>)
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero;
|
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>
|
impl<'de, CS: CipherSuite> serde_::de::Visitor<'de> for ByteVisitor<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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>;
|
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
|
//! 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 generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
|
|
||||||
/// A group representation for use in the key exchange
|
/// 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
|
/// Length of the public key
|
||||||
type PkLen: ArrayLength<u8> + 'static;
|
type PkLen: ArrayLength<u8>;
|
||||||
|
/// Secret key
|
||||||
|
type Sk: Clone;
|
||||||
/// Length of the secret key
|
/// Length of the secret key
|
||||||
type SkLen: ArrayLength<u8> + 'static;
|
type SkLen: ArrayLength<u8>;
|
||||||
|
|
||||||
/// 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;
|
|
||||||
|
|
||||||
/// Serializes `self`
|
/// 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
|
/// 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")]
|
/// Zeroize secret key on drop.
|
||||||
pub mod p256;
|
fn zeroize_sk_on_drop(sk: &mut Self::Sk);
|
||||||
#[cfg(feature = "ristretto255")]
|
|
||||||
pub mod ristretto255;
|
/// Serializes `self`
|
||||||
#[cfg(feature = "x25519")]
|
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen>;
|
||||||
pub mod x25519;
|
|
||||||
|
/// 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::constants::RISTRETTO_BASEPOINT_POINT;
|
||||||
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
|
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
|
||||||
use curve25519_dalek::scalar::Scalar;
|
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 generic_array::GenericArray;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
use voprf::Group;
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use super::KeGroup;
|
use super::KeGroup;
|
||||||
use crate::errors::InternalError;
|
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 PkLen = U32;
|
||||||
|
type Sk = Scalar;
|
||||||
type SkLen = U32;
|
type SkLen = U32;
|
||||||
|
|
||||||
fn from_pk_slice(element_bits: &GenericArray<u8, Self::PkLen>) -> Result<Self, InternalError> {
|
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
|
||||||
CompressedRistretto::from_slice(element_bits)
|
pk.compress().to_bytes().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_pk(bytes: &GenericArray<u8, Self::PkLen>) -> Result<Self::Pk, InternalError> {
|
||||||
|
CompressedRistretto::from_slice(bytes)
|
||||||
.decompress()
|
.decompress()
|
||||||
.ok_or(InternalError::PointError)
|
.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 {
|
loop {
|
||||||
let scalar = {
|
let scalar = {
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
@@ -47,21 +63,121 @@ impl KeGroup for RistrettoPoint {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if scalar != Scalar::zero() {
|
if scalar != Scalar::zero() && scalar.is_canonical() {
|
||||||
break scalar.to_bytes().into();
|
break scalar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn public_key(sk: &GenericArray<u8, Self::SkLen>) -> Self {
|
// Implements the `HashToScalar()` function from
|
||||||
RISTRETTO_BASEPOINT_POINT * Scalar::from_bits(*sk.as_ref())
|
// 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> {
|
fn public_key(sk: &Self::Sk) -> Self::Pk {
|
||||||
self.compress().to_bytes().into()
|
RISTRETTO_BASEPOINT_POINT * sk
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::SkLen> {
|
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
|
||||||
(self * Scalar::from_bits(*sk.as_ref())).to_arr()
|
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
|
//! 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 generic_array::GenericArray;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use x25519_dalek::{PublicKey, StaticSecret};
|
use x25519_dalek::{PublicKey, StaticSecret};
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use super::KeGroup;
|
use super::KeGroup;
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
|
|
||||||
|
/// Implementation for X25519.
|
||||||
|
pub struct X25519;
|
||||||
|
|
||||||
/// The implementation of such a subgroup for Ristretto
|
/// The implementation of such a subgroup for Ristretto
|
||||||
impl KeGroup for PublicKey {
|
impl KeGroup for X25519 {
|
||||||
|
type Pk = PublicKey;
|
||||||
type PkLen = U32;
|
type PkLen = U32;
|
||||||
|
type Sk = StaticSecret;
|
||||||
type SkLen = U32;
|
type SkLen = U32;
|
||||||
|
|
||||||
fn from_pk_slice(element_bits: &GenericArray<u8, Self::PkLen>) -> Result<Self, InternalError> {
|
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
|
||||||
Ok(Self::from(<[u8; 32]>::from(*element_bits)))
|
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];
|
let mut scalar_bytes = [0u8; 32];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
rng.fill_bytes(&mut scalar_bytes);
|
rng.fill_bytes(&mut scalar_bytes);
|
||||||
|
|
||||||
if scalar_bytes != [0u8; 32] {
|
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 {
|
// Implements the `HashToScalar()` function from
|
||||||
Self::from(&StaticSecret::from(<[u8; 32]>::from(*sk)))
|
// 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> {
|
fn public_key(sk: &Self::Sk) -> Self::Pk {
|
||||||
self.to_bytes().into()
|
PublicKey::from(sk)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diffie_hellman(&self, sk: &GenericArray<u8, Self::SkLen>) -> GenericArray<u8, Self::SkLen> {
|
fn diffie_hellman(pk: &Self::Pk, sk: &Self::Sk) -> GenericArray<u8, Self::PkLen> {
|
||||||
StaticSecret::from(<[u8; 32]>::from(*sk))
|
sk.diffie_hellman(pk).to_bytes().into()
|
||||||
.diffie_hellman(self)
|
}
|
||||||
.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::typenum::{IsLess, Le, NonZero, U256};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
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::errors::ProtocolError;
|
||||||
use crate::hash::{Hash, ProxyHash};
|
use crate::hash::{Hash, ProxyHash};
|
||||||
use crate::key_exchange::group::KeGroup;
|
use crate::key_exchange::group::KeGroup;
|
||||||
@@ -46,17 +46,17 @@ where
|
|||||||
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||||
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||||
{
|
{
|
||||||
type KE1State: FromBytes + ToBytes + Zeroize + Clone;
|
type KE1State: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
|
||||||
type KE2State: FromBytes + ToBytes + Zeroize + Clone;
|
type KE2State: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
|
||||||
type KE1Message: FromBytes + ToBytes + Zeroize + Clone;
|
type KE1Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
|
||||||
type KE2Message: FromBytes + ToBytes + Clone;
|
type KE2Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
|
||||||
type KE3Message: FromBytes + ToBytes + Clone;
|
type KE3Message: FromBytes + ToBytes + ZeroizeOnDrop + Clone;
|
||||||
|
|
||||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self::KE1State, Self::KE1Message), ProtocolError>;
|
) -> 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>>(
|
fn generate_ke2<'a, 'b, 'c, 'd, R: RngCore + CryptoRng, S: SecretKey<G>>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
l1_bytes: impl Iterator<Item = &'a [u8]>,
|
l1_bytes: impl Iterator<Item = &'a [u8]>,
|
||||||
@@ -69,7 +69,7 @@ where
|
|||||||
context: &[u8],
|
context: &[u8],
|
||||||
) -> Result<GenerateKe2Result<Self, D, G>, ProtocolError<S::Error>>;
|
) -> 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>(
|
fn generate_ke3<'a, 'b, 'c, 'd>(
|
||||||
l2_component: impl Iterator<Item = &'a [u8]>,
|
l2_component: impl Iterator<Item = &'a [u8]>,
|
||||||
ke2_message: Self::KE2Message,
|
ke2_message: Self::KE2Message,
|
||||||
@@ -82,13 +82,10 @@ where
|
|||||||
context: &[u8],
|
context: &[u8],
|
||||||
) -> Result<GenerateKe3Result<Self, D, G>, ProtocolError>;
|
) -> Result<GenerateKe3Result<Self, D, G>, ProtocolError>;
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn finish_ke(
|
fn finish_ke(
|
||||||
ke3_message: Self::KE3Message,
|
ke3_message: Self::KE3Message,
|
||||||
ke2_state: &Self::KE2State,
|
ke2_state: &Self::KE2State,
|
||||||
) -> Result<Output<D>, ProtocolError>;
|
) -> Result<Output<D>, ProtocolError>;
|
||||||
|
|
||||||
fn ke2_message_size() -> usize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromBytes: Sized {
|
pub trait FromBytes: Sized {
|
||||||
@@ -101,14 +98,13 @@ pub trait ToBytes {
|
|||||||
fn to_bytes(&self) -> GenericArray<u8, Self::Len>;
|
fn to_bytes(&self) -> GenericArray<u8, Self::Len>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub type Ke1StateLen<CS: CipherSuite> =
|
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> =
|
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> =
|
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> =
|
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> =
|
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::convert::TryFrom;
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
|
||||||
use derive_where::DeriveWhere;
|
use derive_where::derive_where;
|
||||||
use digest::core_api::BlockSizeUser;
|
use digest::core_api::BlockSizeUser;
|
||||||
use digest::{Digest, Output};
|
use digest::{Digest, Output};
|
||||||
use generic_array::sequence::Concat;
|
use generic_array::sequence::Concat;
|
||||||
@@ -18,6 +18,7 @@ use generic_array::{ArrayLength, GenericArray};
|
|||||||
use hkdf::{Hkdf, HkdfExtract};
|
use hkdf::{Hkdf, HkdfExtract};
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
use crate::errors::utils::{check_slice_size, check_slice_size_atleast};
|
use crate::errors::utils::{check_slice_size, check_slice_size_atleast};
|
||||||
use crate::errors::{InternalError, ProtocolError};
|
use crate::errors::{InternalError, ProtocolError};
|
||||||
@@ -55,36 +56,63 @@ pub struct TripleDH;
|
|||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
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)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)]
|
||||||
pub struct Ke1State<KG: KeGroup> {
|
pub struct Ke1State<KG: KeGroup> {
|
||||||
client_e_sk: PrivateKey<KG>,
|
client_e_sk: PrivateKey<KG>,
|
||||||
client_nonce: GenericArray<u8, NonceLen>,
|
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
|
/// The first key exchange message
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
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)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
|
||||||
pub struct Ke1Message<KG: KeGroup> {
|
pub struct Ke1Message<KG: KeGroup> {
|
||||||
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
pub(crate) client_nonce: GenericArray<u8, NonceLen>,
|
||||||
pub(crate) client_e_pk: PublicKey<KG>,
|
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
|
/// The server state produced after the second key exchange message
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
derive(serde_::Deserialize, serde_::Serialize),
|
||||||
serde(bound = "", crate = "serde_")
|
serde(bound = "", crate = "serde_")
|
||||||
)]
|
)]
|
||||||
#[derive(DeriveWhere)]
|
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
|
||||||
pub struct Ke2State<D: Hash>
|
pub struct Ke2State<D: Hash>
|
||||||
where
|
where
|
||||||
D::Core: ProxyHash,
|
D::Core: ProxyHash,
|
||||||
@@ -96,14 +124,41 @@ where
|
|||||||
session_key: Output<D>,
|
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
|
/// The second key exchange message
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
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)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
|
||||||
pub struct Ke2Message<D: Hash, KG: KeGroup>
|
pub struct Ke2Message<D: Hash, KG: KeGroup>
|
||||||
where
|
where
|
||||||
D::Core: ProxyHash,
|
D::Core: ProxyHash,
|
||||||
@@ -115,13 +170,32 @@ where
|
|||||||
mac: Output<D>,
|
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
|
/// The third key exchange message
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
derive(serde_::Deserialize, serde_::Serialize),
|
||||||
serde(bound = "", crate = "serde_")
|
serde(bound = "", crate = "serde_")
|
||||||
)]
|
)]
|
||||||
#[derive(DeriveWhere)]
|
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
pub struct Ke3Message<D: Hash>
|
pub struct Ke3Message<D: Hash>
|
||||||
where
|
where
|
||||||
@@ -132,6 +206,25 @@ where
|
|||||||
mac: Output<D>,
|
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 //
|
// High-level Implementations //
|
||||||
// ========================== //
|
// ========================== //
|
||||||
@@ -210,13 +303,13 @@ where
|
|||||||
.chain_iter(id_s.into_iter())
|
.chain_iter(id_s.into_iter())
|
||||||
.chain_iter(l2_bytes)
|
.chain_iter(l2_bytes)
|
||||||
.chain(server_nonce)
|
.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>(
|
let result = derive_3dh_keys::<D, KG, S>(
|
||||||
TripleDHComponents {
|
TripleDHComponents {
|
||||||
pk1: ke1_message.client_e_pk.clone(),
|
pk1: ke1_message.client_e_pk.clone(),
|
||||||
sk1: server_e_kp.private().clone(),
|
sk1: server_e_kp.private().clone(),
|
||||||
pk2: ke1_message.client_e_pk,
|
pk2: ke1_message.client_e_pk.clone(),
|
||||||
sk2: server_s_sk,
|
sk2: server_s_sk,
|
||||||
pk3: client_s_pk,
|
pk3: client_s_pk,
|
||||||
sk3: server_e_kp.private().clone(),
|
sk3: server_e_kp.private().clone(),
|
||||||
@@ -268,7 +361,7 @@ where
|
|||||||
.chain_iter(serialized_credential_request)
|
.chain_iter(serialized_credential_request)
|
||||||
.chain_iter(id_s)
|
.chain_iter(id_s)
|
||||||
.chain_iter(l2_component)
|
.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>>(
|
let result = derive_3dh_keys::<D, KG, PrivateKey<KG>>(
|
||||||
TripleDHComponents {
|
TripleDHComponents {
|
||||||
@@ -322,10 +415,6 @@ where
|
|||||||
|
|
||||||
Ok(ke2_state.session_key.clone())
|
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")?;
|
let checked_bytes = check_slice_size_atleast(bytes, key_len + nonce_len, "ke1_state")?;
|
||||||
|
|
||||||
Ok(Self {
|
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(
|
client_nonce: GenericArray::clone_from_slice(
|
||||||
&checked_bytes[key_len..key_len + nonce_len],
|
&checked_bytes[key_len..key_len + nonce_len],
|
||||||
),
|
),
|
||||||
@@ -506,7 +595,7 @@ where
|
|||||||
type Len = Sum<KG::SkLen, NonceLen>;
|
type Len = Sum<KG::SkLen, NonceLen>;
|
||||||
|
|
||||||
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
|
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 {
|
Ok(Self {
|
||||||
client_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]),
|
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>;
|
type Len = Sum<NonceLen, KG::PkLen>;
|
||||||
|
|
||||||
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
|
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
|
// Check the public key bytes
|
||||||
let server_e_pk = KeyPair::<KG>::check_public_key(PublicKey::from_bytes(
|
let server_e_pk = PublicKey::deserialize(&unchecked_server_e_pk[..key_len])?;
|
||||||
&unchecked_server_e_pk[..key_len],
|
|
||||||
)?)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
server_nonce: GenericArray::clone_from_slice(&checked_nonce[..nonce_len]),
|
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),
|
mac: GenericArray::clone_from_slice(checked_mac),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -628,7 +715,7 @@ where
|
|||||||
|
|
||||||
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
|
fn to_bytes(&self) -> GenericArray<u8, Self::Len> {
|
||||||
self.server_nonce
|
self.server_nonce
|
||||||
.concat(self.server_e_pk.to_arr())
|
.concat(self.server_e_pk.to_bytes())
|
||||||
.concat(self.mac.clone())
|
.concat(self.mac.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -638,9 +725,11 @@ where
|
|||||||
D::Core: ProxyHash,
|
D::Core: ProxyHash,
|
||||||
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||||
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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]> {
|
fn to_bytes_without_mac(&self) -> GenericArray<u8, Sum<NonceLen, KG::PkLen>> {
|
||||||
[self.server_nonce.as_slice(), self.server_e_pk.as_slice()].into_iter()
|
self.server_nonce.concat(self.server_e_pk.to_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+74
-162
@@ -9,16 +9,14 @@
|
|||||||
|
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use core::ops::Deref;
|
use derive_where::derive_where;
|
||||||
|
|
||||||
use derive_where::DeriveWhere;
|
|
||||||
use generic_array::typenum::Unsigned;
|
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use zeroize::Zeroize;
|
use zeroize::ZeroizeOnDrop;
|
||||||
|
|
||||||
use crate::errors::{InternalError, ProtocolError};
|
use crate::errors::{InternalError, ProtocolError};
|
||||||
use crate::key_exchange::group::KeGroup;
|
use crate::key_exchange::group::KeGroup;
|
||||||
|
use crate::serialization::GenericArrayExt;
|
||||||
|
|
||||||
/// A Keypair trait with public-private verification
|
/// A Keypair trait with public-private verification
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@@ -26,15 +24,14 @@ use crate::key_exchange::group::KeGroup;
|
|||||||
derive(serde_::Deserialize, serde_::Serialize),
|
derive(serde_::Deserialize, serde_::Serialize),
|
||||||
serde(
|
serde(
|
||||||
bound(
|
bound(
|
||||||
deserialize = "S: serde_::Deserialize<'de>",
|
deserialize = "KG::Pk: serde_::Deserialize<'de>, S: serde_::Deserialize<'de>",
|
||||||
serialize = "S: serde_::Serialize"
|
serialize = "KG::Pk: serde_::Serialize, S: serde_::Serialize"
|
||||||
),
|
),
|
||||||
crate = "serde_"
|
crate = "serde_"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#[derive(DeriveWhere)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(Clone, Zeroize(drop))]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk, S)]
|
||||||
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; S)]
|
|
||||||
pub struct KeyPair<KG: KeGroup, S: SecretKey<KG> = PrivateKey<KG>> {
|
pub struct KeyPair<KG: KeGroup, S: SecretKey<KG> = PrivateKey<KG>> {
|
||||||
pk: PublicKey<KG>,
|
pk: PublicKey<KG>,
|
||||||
sk: S,
|
sk: S,
|
||||||
@@ -51,14 +48,6 @@ impl<KG: KeGroup, S: SecretKey<KG>> KeyPair<KG, S> {
|
|||||||
&self.sk
|
&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
|
/// Obtains a KeyPair from a slice representing the private key
|
||||||
pub fn from_private_key_slice(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> {
|
pub fn from_private_key_slice(input: &[u8]) -> Result<Self, ProtocolError<S::Error>> {
|
||||||
Self::from_private_key(S::deserialize(input)?)
|
Self::from_private_key(S::deserialize(input)?)
|
||||||
@@ -77,14 +66,18 @@ impl<KG: KeGroup> KeyPair<KG> {
|
|||||||
let sk = KG::random_sk(rng);
|
let sk = KG::random_sk(rng);
|
||||||
let pk = KG::public_key(&sk);
|
let pk = KG::public_key(&sk);
|
||||||
Self {
|
Self {
|
||||||
pk: PublicKey(Key(pk.to_arr())),
|
pk: PublicKey(pk),
|
||||||
sk: PrivateKey(Key(sk)),
|
sk: PrivateKey(sk),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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
|
/// Test-only strategy returning a proptest Strategy based on
|
||||||
/// generate_random
|
/// generate_random
|
||||||
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
|
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.
|
/// Wrapper around a Key to enforce that it's a private one.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
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)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)]
|
||||||
pub struct PrivateKey<KG: KeGroup>(Key<KG::SkLen>);
|
pub struct PrivateKey<KG: KeGroup>(KG::Sk);
|
||||||
|
|
||||||
// This can't be derived because of the use of a generic parameter
|
impl<KG: KeGroup> Drop for PrivateKey<KG> {
|
||||||
impl<KG: KeGroup> Deref for PrivateKey<KG> {
|
fn drop(&mut self) {
|
||||||
type Target = Key<KG::SkLen>;
|
KG::zeroize_sk_on_drop(&mut self.0)
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<KG: KeGroup> ZeroizeOnDrop for PrivateKey<KG> {}
|
||||||
|
|
||||||
impl<KG: KeGroup> PrivateKey<KG> {
|
impl<KG: KeGroup> PrivateKey<KG> {
|
||||||
/// Convert from bytes
|
/// Convert from bytes
|
||||||
pub fn from_arr(key_bytes: GenericArray<u8, KG::SkLen>) -> Self {
|
pub fn from_bytes(key_bytes: &GenericArray<u8, KG::SkLen>) -> Result<Self, InternalError> {
|
||||||
PrivateKey(Key(key_bytes))
|
KG::deserialize_sk(key_bytes).map(Self)
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait specifying the requirements for a private key container
|
/// 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`
|
/// Custom error type that can be passed down to `InternalError::Custom`
|
||||||
type Error;
|
type Error;
|
||||||
/// Serialization size in bytes.
|
/// Serialization size in bytes.
|
||||||
@@ -197,20 +159,19 @@ impl<KG: KeGroup> SecretKey<KG> for PrivateKey<KG> {
|
|||||||
&self,
|
&self,
|
||||||
pk: PublicKey<KG>,
|
pk: PublicKey<KG>,
|
||||||
) -> Result<GenericArray<u8, KG::PkLen>, InternalError> {
|
) -> Result<GenericArray<u8, KG::PkLen>, InternalError> {
|
||||||
let pk = KG::from_pk_slice(&pk)?;
|
Ok(KG::diffie_hellman(&pk.0, &self.0))
|
||||||
Ok(pk.diffie_hellman(self))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn public_key(&self) -> Result<PublicKey<KG>, InternalError> {
|
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> {
|
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||||
self.to_arr()
|
KG::serialize_sk(&self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
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(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
derive(serde_::Deserialize, serde_::Serialize),
|
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)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)]
|
||||||
pub struct PublicKey<KG: KeGroup>(Key<KG::PkLen>);
|
pub struct PublicKey<KG: KeGroup>(KG::Pk);
|
||||||
|
|
||||||
impl<KG: KeGroup> Deref for PublicKey<KG> {
|
|
||||||
type Target = Key<KG::PkLen>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<KG: KeGroup> PublicKey<KG> {
|
impl<KG: KeGroup> PublicKey<KG> {
|
||||||
/// Convert from bytes
|
/// Convert from bytes
|
||||||
pub fn from_arr(key_bytes: GenericArray<u8, KG::PkLen>) -> Self {
|
pub fn from_bytes(key_bytes: &GenericArray<u8, KG::PkLen>) -> Result<Self, InternalError> {
|
||||||
Self(Key(key_bytes))
|
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
|
/// Convert from slice
|
||||||
pub fn from_bytes(key_bytes: &[u8]) -> Result<Self, InternalError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
|
||||||
if key_bytes.len() == KG::PkLen::USIZE {
|
GenericArray::try_from_slice(input).and_then(Self::from_bytes)
|
||||||
Ok(Self::from_arr(GenericArray::from_slice(key_bytes).clone()))
|
|
||||||
} else {
|
|
||||||
Err(InternalError::InvalidByteSequence)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use core::slice::from_raw_parts;
|
|
||||||
use std::vec;
|
|
||||||
|
|
||||||
use generic_array::typenum::Unsigned;
|
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
use crate::util;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_zeroize_key() -> Result<(), ProtocolError> {
|
fn test_zeroize_key() {
|
||||||
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 inner<G: KeGroup>() {
|
fn inner<G: KeGroup>() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let mut keypair = KeyPair::<G>::generate_random(&mut rng);
|
let mut key = PrivateKey::<G>(G::random_sk(&mut rng));
|
||||||
let pk_ptr = keypair.pk.as_ptr();
|
util::test_zeroize_on_drop(&mut key);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<curve25519_dalek::ristretto::RistrettoPoint>();
|
inner::<crate::Ristretto255>();
|
||||||
#[cfg(feature = "p256")]
|
inner::<::p256::NistP256>();
|
||||||
inner::<p256_::PublicKey>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! test {
|
macro_rules! test {
|
||||||
@@ -317,12 +239,6 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
proptest! {
|
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]
|
#[test]
|
||||||
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
|
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
|
||||||
let pk = kp.public();
|
let pk = kp.public();
|
||||||
@@ -342,10 +258,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn private_key_slice(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
|
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 = 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);
|
prop_assert_eq!(sk_bytes, kp2_private_bytes);
|
||||||
}
|
}
|
||||||
@@ -355,16 +271,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
test!(ristretto, curve25519_dalek::ristretto::RistrettoPoint);
|
test!(ristretto, crate::Ristretto255);
|
||||||
#[cfg(feature = "p256")]
|
test!(p256, ::p256::NistP256);
|
||||||
test!(p256, p256_::PublicKey);
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remote_key() {
|
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 rand::rngs::OsRng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -379,19 +290,20 @@ mod tests {
|
|||||||
|
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for Default {
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
type OprfGroup = KeCurve;
|
type OprfGroup = crate::Ristretto255;
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
type OprfGroup = p256_::ProjectivePoint;
|
type OprfGroup = ::p256::NistP256;
|
||||||
type KeGroup = KeCurve;
|
|
||||||
type KeyExchange = crate::key_exchange::tripledh::TripleDH;
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
type Hash = sha2::Sha512;
|
type KeGroup = crate::Ristretto255;
|
||||||
#[cfg(not(feature = "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;
|
type SlowHash = crate::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Zeroize)]
|
type KeCurve = <Default as CipherSuite>::KeGroup;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct RemoteKey(PrivateKey<KeCurve>);
|
struct RemoteKey(PrivateKey<KeCurve>);
|
||||||
|
|
||||||
impl SecretKey<KeCurve> for RemoteKey {
|
impl SecretKey<KeCurve> for RemoteKey {
|
||||||
@@ -422,7 +334,7 @@ mod tests {
|
|||||||
const PASSWORD: &str = "password";
|
const PASSWORD: &str = "password";
|
||||||
|
|
||||||
let sk = KeCurve::random_sk(&mut OsRng);
|
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 keypair = KeyPair::from_private_key(sk).unwrap();
|
||||||
|
|
||||||
let server_setup = ServerSetup::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair);
|
let server_setup = ServerSetup::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair);
|
||||||
|
|||||||
+81
-109
@@ -14,7 +14,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Minimum Supported Rust Version
|
//! ### Minimum Supported Rust Version
|
||||||
//!
|
//!
|
||||||
//! Rust **1.56** or higher.
|
//! Rust **1.57** or higher.
|
||||||
//!
|
//!
|
||||||
//! # Overview
|
//! # Overview
|
||||||
//!
|
//!
|
||||||
@@ -33,10 +33,9 @@
|
|||||||
//! use opaque_ke::CipherSuite;
|
//! use opaque_ke::CipherSuite;
|
||||||
//! struct Default;
|
//! struct Default;
|
||||||
//! impl CipherSuite for Default {
|
//! impl CipherSuite for Default {
|
||||||
//! type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! type Hash = sha2::Sha512;
|
|
||||||
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
@@ -59,18 +58,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! use rand::rngs::OsRng;
|
//! use rand::rngs::OsRng;
|
||||||
@@ -110,18 +107,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! use opaque_ke::ClientRegistration;
|
//! use opaque_ke::ClientRegistration;
|
||||||
@@ -150,18 +145,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -199,18 +192,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -249,18 +240,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -304,18 +293,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -343,18 +330,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -408,18 +393,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -466,18 +449,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -564,18 +545,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -663,18 +642,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -746,18 +723,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -796,18 +771,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -857,18 +830,16 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
@@ -955,27 +926,25 @@
|
|||||||
//! # struct Default;
|
//! # struct Default;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type OprfGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type KeGroup = opaque_ke::Ristretto255;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha512;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[cfg(not(feature = "ristretto255"))]
|
//! # #[cfg(not(feature = "ristretto255"))]
|
||||||
//! # impl CipherSuite for Default {
|
//! # impl CipherSuite for Default {
|
||||||
//! # type OprfGroup = p256_::ProjectivePoint;
|
//! # type OprfGroup = p256::NistP256;
|
||||||
//! # type KeGroup = p256_::PublicKey;
|
//! # type KeGroup = p256::NistP256;
|
||||||
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH;
|
||||||
//! # type Hash = sha2::Sha256;
|
|
||||||
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
//! # type SlowHash = opaque_ke::slow_hash::NoOpHash;
|
||||||
//! # }
|
//! # }
|
||||||
//! # #[derive(Debug)]
|
//! # #[derive(Debug)]
|
||||||
//! # struct YourRemoteKeyError;
|
//! # struct YourRemoteKeyError;
|
||||||
//! # #[derive(Clone, Zeroize)]
|
//! # #[derive(Clone)]
|
||||||
//! # struct YourRemoteKey(PrivateKey<<Default as CipherSuite>::KeGroup>);
|
//! # struct YourRemoteKey(<<Default as CipherSuite>::KeGroup as KeGroup>::Sk);
|
||||||
//! # impl YourRemoteKey {
|
//! # impl YourRemoteKey {
|
||||||
//! # fn diffie_hellman(&self, pk: &[u8]) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, YourRemoteKeyError> { todo!() }
|
//! # 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 {
|
//! impl SecretKey<<Default as CipherSuite>::KeGroup> for YourRemoteKey {
|
||||||
//! type Error = YourRemoteKeyError;
|
//! type Error = YourRemoteKeyError;
|
||||||
@@ -985,14 +954,13 @@
|
|||||||
//! &self,
|
//! &self,
|
||||||
//! pk: PublicKey<<Default as CipherSuite>::KeGroup>,
|
//! pk: PublicKey<<Default as CipherSuite>::KeGroup>,
|
||||||
//! ) -> Result<GenericArray<u8, <<Default as CipherSuite>::KeGroup as KeGroup>::PkLen>, InternalError<Self::Error>> {
|
//! ) -> 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(
|
//! fn public_key(
|
||||||
//! &self
|
//! &self
|
||||||
//! ) -> Result<PublicKey<<Default as CipherSuite>::KeGroup>, InternalError<Self::Error>> {
|
//! ) -> Result<PublicKey<<Default as CipherSuite>::KeGroup>, InternalError<Self::Error>> {
|
||||||
//! YourRemoteKey::public_key(self).map(PublicKey::from_arr)
|
//! PublicKey::from_bytes(&YourRemoteKey::public_key(self).map_err(InternalError::Custom)?).map_err(InternalError::into_custom)
|
||||||
//! .map_err(InternalError::Custom)
|
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
//! 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 keypair = KeyPair::from_private_key(remote_key).unwrap();
|
||||||
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key(&mut OsRng, keypair);
|
//! 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
|
//! `ristretto255_fiat_u32`. Any `ristretto255_*` backend feature will enable
|
||||||
//! the `ristretto255` feature, which can be used too, but keep in mind that
|
//! the `ristretto255` feature, which can be used too, but keep in mind that
|
||||||
//! `curve25519-dalek` will fail to compile without a selected backend. This
|
//! `curve25519-dalek` will fail to compile without a selected backend. This
|
||||||
//! enables the use of `curve25519_dalek::ristretto::RistrettoPoint` as a
|
//! enables the use of [`Ristretto255`] as a `KeGroup` and `OprfGroup`.
|
||||||
//! `KeGroup` and `OprfGroup`.
|
|
||||||
//!
|
//!
|
||||||
//! - The `x25519` feature is similar to the `ristretto255` feature and requires
|
//! - 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
|
//! 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)
|
//! - 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
|
//! and enables parallel formulas, using either AVX2 or AVX512-IFMA. This will
|
||||||
//! automatically enable the `ristretto255_u64` feature and requires Rust
|
//! automatically enable the `ristretto255_u64` feature and requires Rust
|
||||||
//! nightly.
|
//! nightly.
|
||||||
//!
|
//!
|
||||||
//! - The `p256` feature enables the use of `p256::PublicKey` as a `KeGroup` and
|
//! - The `p256` feature enables the use of [`p256::NistP256`] as a `KeGroup`
|
||||||
//! `p256::ProjectivePoint` as a `OprfGroup` for `CipherSuite`. Note that this
|
//! and a `OprfGroup` for `CipherSuite`.
|
||||||
//! is currently an experimental feature ⚠️, and is not yet ready for
|
|
||||||
//! production use.
|
|
||||||
//!
|
//!
|
||||||
//! - The `bench` feature is used only for running performance benchmarks for
|
//! - The `bench` feature is used only for running performance benchmarks for
|
||||||
//! this implementation.
|
//! 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]
|
#![no_std]
|
||||||
#![warn(clippy::cargo, missing_docs)]
|
#![warn(clippy::cargo, missing_docs)]
|
||||||
#![allow(clippy::multiple_crate_versions, type_alias_bounds)]
|
#![allow(clippy::multiple_crate_versions, type_alias_bounds)]
|
||||||
@@ -1074,6 +1041,7 @@ mod messages;
|
|||||||
mod opaque;
|
mod opaque;
|
||||||
mod serialization;
|
mod serialization;
|
||||||
pub mod slow_hash;
|
pub mod slow_hash;
|
||||||
|
mod util;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@@ -1083,6 +1051,10 @@ mod tests;
|
|||||||
pub use ciphersuite::CipherSuite;
|
pub use ciphersuite::CipherSuite;
|
||||||
pub use rand;
|
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::{
|
pub use crate::messages::{
|
||||||
CredentialFinalization, CredentialFinalizationLen, CredentialRequest, CredentialRequestLen,
|
CredentialFinalization, CredentialFinalizationLen, CredentialRequest, CredentialRequestLen,
|
||||||
CredentialResponse, CredentialResponseLen, RegistrationRequest, RegistrationRequestLen,
|
CredentialResponse, CredentialResponseLen, RegistrationRequest, RegistrationRequestLen,
|
||||||
|
|||||||
Executable → Regular
+179
-132
@@ -9,26 +9,28 @@
|
|||||||
|
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
|
||||||
use derive_where::DeriveWhere;
|
use derive_where::derive_where;
|
||||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||||
use digest::Output;
|
use digest::{Output, OutputSizeUser};
|
||||||
use generic_array::sequence::Concat;
|
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 generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
use voprf::Group;
|
use voprf::Group;
|
||||||
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
use crate::ciphersuite::CipherSuite;
|
use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
|
||||||
use crate::envelope::{Envelope, EnvelopeLen};
|
use crate::envelope::{Envelope, EnvelopeLen};
|
||||||
use crate::errors::utils::{check_slice_size, check_slice_size_atleast};
|
use crate::errors::utils::{check_slice_size, check_slice_size_atleast};
|
||||||
use crate::errors::ProtocolError;
|
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::group::KeGroup;
|
||||||
use crate::key_exchange::traits::{
|
use crate::key_exchange::traits::{
|
||||||
FromBytes, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, ToBytes,
|
FromBytes, Ke1MessageLen, Ke2MessageLen, Ke3MessageLen, KeyExchange, ToBytes,
|
||||||
};
|
};
|
||||||
use crate::key_exchange::tripledh::NonceLen;
|
use crate::key_exchange::tripledh::NonceLen;
|
||||||
use crate::keypair::{KeyPair, PublicKey, SecretKey};
|
use crate::keypair::{PublicKey, SecretKey};
|
||||||
use crate::opaque::{MaskedResponse, MaskedResponseLen, ServerSetup};
|
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
|
/// The message sent by the client to the server, to initiate registration
|
||||||
#[derive(DeriveWhere)]
|
|
||||||
#[derive_where(Clone)]
|
#[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>
|
pub struct RegistrationRequest<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// 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);
|
impl_serialize_and_deserialize_for!(RegistrationRequest);
|
||||||
|
|
||||||
/// The answer sent by the server to the user, upon reception of the
|
/// The answer sent by the server to the user, upon reception of the
|
||||||
/// registration attempt
|
/// registration attempt
|
||||||
#[derive(DeriveWhere)]
|
|
||||||
#[derive_where(Clone)]
|
#[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>
|
pub struct RegistrationResponse<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// 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
|
/// Server's static public key
|
||||||
pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
|
pub(crate) server_s_pk: PublicKey<CS::KeGroup>,
|
||||||
}
|
}
|
||||||
@@ -73,101 +79,133 @@ impl_serialize_and_deserialize_for!(
|
|||||||
RegistrationResponse
|
RegistrationResponse
|
||||||
where
|
where
|
||||||
// RegistrationResponse: KgPk + KePk
|
// 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>,
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The final message from the client, containing sealed cryptographic
|
/// The final message from the client, containing sealed cryptographic
|
||||||
/// identifiers
|
/// identifiers
|
||||||
#[derive(DeriveWhere)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize(drop))]
|
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <CS::KeGroup as KeGroup>::Pk)]
|
||||||
pub struct RegistrationUpload<CS: CipherSuite>
|
pub struct RegistrationUpload<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// The "envelope" generated by the user, containing sealed cryptographic
|
||||||
/// identifiers
|
/// identifiers
|
||||||
pub(crate) envelope: Envelope<CS>,
|
pub(crate) envelope: Envelope<CS>,
|
||||||
/// The masking key used to mask the envelope
|
/// 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
|
/// The user's public key
|
||||||
pub(crate) client_s_pk: PublicKey<CS::KeGroup>,
|
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!(
|
impl_serialize_and_deserialize_for!(
|
||||||
RegistrationUpload
|
RegistrationUpload
|
||||||
where
|
where
|
||||||
// Envelope: Nonce + Hash
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> | Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The message sent by the user to the server, to initiate registration
|
/// The message sent by the user to the server, to initiate registration
|
||||||
#[derive(DeriveWhere)]
|
#[derive_where(Clone, ZeroizeOnDrop)]
|
||||||
#[derive_where(Clone, Zeroize)]
|
|
||||||
#[derive_where(
|
#[derive_where(
|
||||||
Debug, Eq, Hash, PartialEq;
|
Debug, Eq, Hash, PartialEq;
|
||||||
CS::OprfGroup,
|
voprf::BlindedElement<CS::OprfGroup>,
|
||||||
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
|
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
|
||||||
)]
|
)]
|
||||||
pub struct CredentialRequest<CS: CipherSuite>
|
pub struct CredentialRequest<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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) blinded_element: voprf::BlindedElement<CS::OprfGroup>,
|
||||||
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message,
|
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_serialize_and_deserialize_for!(
|
impl_serialize_and_deserialize_for!(
|
||||||
CredentialRequest
|
CredentialRequest
|
||||||
where
|
where
|
||||||
// CredentialRequest: KgPk + Ke1Message
|
// CredentialRequest: KgPk + Ke1Message
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// The answer sent by the server to the user, upon reception of the login
|
/// The answer sent by the server to the user, upon reception of the login
|
||||||
/// attempt
|
/// attempt
|
||||||
#[derive(DeriveWhere)]
|
|
||||||
#[derive_where(Clone)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(
|
#[derive_where(
|
||||||
Debug, Eq, Hash, PartialEq;
|
Debug, Eq, Hash, PartialEq;
|
||||||
CS::OprfGroup,
|
voprf::EvaluationElement<CS::OprfGroup>,
|
||||||
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE2Message,
|
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE2Message,
|
||||||
)]
|
)]
|
||||||
pub struct CredentialResponse<CS: CipherSuite>
|
pub struct CredentialResponse<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// 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) masking_nonce: GenericArray<u8, NonceLen>,
|
||||||
pub(crate) masked_response: MaskedResponse<CS>,
|
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!(
|
impl_serialize_and_deserialize_for!(
|
||||||
CredentialResponse
|
CredentialResponse
|
||||||
where
|
where
|
||||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||||
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
|
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
|
||||||
ArrayLength<u8> | Add<MaskedResponseLen<CS>>,
|
ArrayLength<u8> | Add<MaskedResponseLen<CS>>,
|
||||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>:
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> | Add<<CS::KeGroup as KeGroup>::PkLen>,
|
ArrayLength<u8> | Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
// 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
|
/// The answer sent by the client to the server, upon reception of the sealed
|
||||||
/// envelope
|
/// envelope
|
||||||
#[derive(DeriveWhere)]
|
|
||||||
#[derive_where(Clone)]
|
#[derive_where(Clone)]
|
||||||
#[derive_where(
|
#[derive_where(
|
||||||
Debug, Eq, Hash, PartialEq;
|
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>
|
pub struct CredentialFinalization<CS: CipherSuite>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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);
|
impl_serialize_and_deserialize_for!(CredentialFinalization);
|
||||||
@@ -200,25 +240,26 @@ impl_serialize_and_deserialize_for!(CredentialFinalization);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
/// Length of [`RegistrationRequest`] in bytes for serialization.
|
/// 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>
|
impl<CS: CipherSuite> RegistrationRequest<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Only used for testing purposes
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn get_blinded_element_for_testing(
|
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
|
||||||
&self,
|
|
||||||
) -> voprf::BlindedElement<CS::OprfGroup, CS::Hash> {
|
|
||||||
self.blinded_element.clone()
|
self.blinded_element.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialization into bytes
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, RegistrationRequestLen<CS>> {
|
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
|
/// Deserialization from bytes
|
||||||
@@ -231,38 +272,37 @@ where
|
|||||||
|
|
||||||
/// Length of [`RegistrationResponse`] in bytes for serialization.
|
/// Length of [`RegistrationResponse`] in bytes for serialization.
|
||||||
pub type RegistrationResponseLen<CS: CipherSuite> =
|
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>
|
impl<CS: CipherSuite> RegistrationResponse<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
|
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
|
||||||
where
|
where
|
||||||
// RegistrationResponse: KgPk + KePk
|
// 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>,
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
self.evaluation_element
|
<OprfGroup<CS> as Group>::serialize_elem(self.evaluation_element.value())
|
||||||
.value()
|
.concat(self.server_s_pk.to_bytes())
|
||||||
.to_arr()
|
|
||||||
.concat(self.server_s_pk.to_arr())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||||
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
|
let elem_len = <OprfGroup<CS> as Group>::ElemLen::USIZE;
|
||||||
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
||||||
let checked_slice =
|
let checked_slice =
|
||||||
check_slice_size(input, elem_len + key_len, "registration_response_bytes")?;
|
check_slice_size(input, elem_len + key_len, "registration_response_bytes")?;
|
||||||
|
|
||||||
// Ensure that public key is valid
|
// Ensure that public key is valid
|
||||||
let server_s_pk = KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
|
let server_s_pk = PublicKey::deserialize(&checked_slice[elem_len..])?;
|
||||||
&checked_slice[elem_len..],
|
|
||||||
)?)?;
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
evaluation_element: voprf::EvaluationElement::deserialize(&checked_slice[..elem_len])?,
|
evaluation_element: voprf::EvaluationElement::deserialize(&checked_slice[..elem_len])?,
|
||||||
@@ -273,7 +313,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Only used for tests, where we can set the beta value to test for the
|
/// Only used for tests, where we can set the beta value to test for the
|
||||||
/// reflection error case
|
/// 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 {
|
Self {
|
||||||
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
||||||
server_s_pk: self.server_s_pk.clone(),
|
server_s_pk: self.server_s_pk.clone(),
|
||||||
@@ -283,28 +323,31 @@ where
|
|||||||
|
|
||||||
/// Length of [`RegistrationUpload`] in bytes for serialization.
|
/// Length of [`RegistrationUpload`] in bytes for serialization.
|
||||||
pub type RegistrationUploadLen<CS: CipherSuite> =
|
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>
|
impl<CS: CipherSuite> RegistrationUpload<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, RegistrationUploadLen<CS>>
|
pub fn serialize(&self) -> GenericArray<u8, RegistrationUploadLen<CS>>
|
||||||
where
|
where
|
||||||
// Envelope: Nonce + Hash
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
self.client_s_pk
|
self.client_s_pk
|
||||||
.to_arr()
|
.to_bytes()
|
||||||
.concat(self.masking_key.clone())
|
.concat(self.masking_key.clone())
|
||||||
.concat(self.envelope.serialize())
|
.concat(self.envelope.serialize())
|
||||||
}
|
}
|
||||||
@@ -312,7 +355,7 @@ where
|
|||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||||
let key_len = <CS::KeGroup as KeGroup>::PkLen::USIZE;
|
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 =
|
let checked_slice =
|
||||||
check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?;
|
check_slice_size_atleast(input, key_len + hash_len, "registration_upload_bytes")?;
|
||||||
let envelope = Envelope::<CS>::deserialize(&checked_slice[key_len + hash_len..])?;
|
let envelope = Envelope::<CS>::deserialize(&checked_slice[key_len + hash_len..])?;
|
||||||
@@ -321,9 +364,7 @@ where
|
|||||||
masking_key: GenericArray::clone_from_slice(
|
masking_key: GenericArray::clone_from_slice(
|
||||||
&checked_slice[key_len..key_len + hash_len],
|
&checked_slice[key_len..key_len + hash_len],
|
||||||
),
|
),
|
||||||
client_s_pk: KeyPair::<CS::KeGroup>::check_public_key(PublicKey::from_bytes(
|
client_s_pk: PublicKey::deserialize(&checked_slice[..key_len])?,
|
||||||
&checked_slice[..key_len],
|
|
||||||
)?)?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +373,7 @@ where
|
|||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
server_setup: &ServerSetup<CS, S>,
|
server_setup: &ServerSetup<CS, S>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut masking_key = Output::<CS::Hash>::default();
|
let mut masking_key = Output::<OprfHash<CS>>::default();
|
||||||
rng.fill_bytes(&mut masking_key);
|
rng.fill_bytes(&mut masking_key);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@@ -345,29 +386,30 @@ where
|
|||||||
|
|
||||||
/// Length of [`CredentialRequest`] in bytes for serialization.
|
/// Length of [`CredentialRequest`] in bytes for serialization.
|
||||||
pub type CredentialRequestLen<CS: CipherSuite> =
|
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>
|
impl<CS: CipherSuite> CredentialRequest<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, CredentialRequestLen<CS>>
|
pub fn serialize(&self) -> GenericArray<u8, CredentialRequestLen<CS>>
|
||||||
where
|
where
|
||||||
// CredentialRequest: KgPk + Ke1Message
|
// CredentialRequest: KgPk + Ke1Message
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
self.blinded_element
|
<OprfGroup<CS> as Group>::serialize_elem(self.blinded_element.value())
|
||||||
.value()
|
|
||||||
.to_arr()
|
|
||||||
.concat(self.ke1_message.to_bytes())
|
.concat(self.ke1_message.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn serialize_iter<'a>(
|
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>>,
|
ke1_message: &'a GenericArray<u8, Ke1MessageLen<CS>>,
|
||||||
) -> impl Iterator<Item = &'a [u8]> {
|
) -> impl Iterator<Item = &'a [u8]> {
|
||||||
[blinded_element.as_slice(), ke1_message].into_iter()
|
[blinded_element.as_slice(), ke1_message].into_iter()
|
||||||
@@ -375,23 +417,22 @@ where
|
|||||||
|
|
||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||||
let elem_len = <CS::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")?;
|
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
|
// Check that the message is actually containing an element of the correct
|
||||||
// subgroup
|
// subgroup
|
||||||
let blinded_element = voprf::BlindedElement::<CS::OprfGroup, CS::Hash>::deserialize(
|
let blinded_element =
|
||||||
&checked_slice[..elem_len],
|
voprf::BlindedElement::<CS::OprfGroup>::deserialize(&checked_slice[..elem_len])?;
|
||||||
)?;
|
|
||||||
|
|
||||||
// Throw an error if the identity group element is encountered
|
// 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);
|
return Err(ProtocolError::IdentityGroupElementError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ke1_message =
|
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..],
|
&checked_slice[elem_len..],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -403,9 +444,7 @@ where
|
|||||||
|
|
||||||
/// Only used for testing purposes
|
/// Only used for testing purposes
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn get_blinded_element_for_testing(
|
pub fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfGroup> {
|
||||||
&self,
|
|
||||||
) -> voprf::BlindedElement<CS::OprfGroup, CS::Hash> {
|
|
||||||
self.blinded_element.clone()
|
self.blinded_element.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,40 +454,42 @@ pub type CredentialResponseLen<CS: CipherSuite> =
|
|||||||
Sum<CredentialResponseWithoutKeLen<CS>, Ke2MessageLen<CS>>;
|
Sum<CredentialResponseWithoutKeLen<CS>, Ke2MessageLen<CS>>;
|
||||||
|
|
||||||
pub(crate) type CredentialResponseWithoutKeLen<CS: CipherSuite> =
|
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>
|
impl<CS: CipherSuite> CredentialResponse<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, CredentialResponseLen<CS>>
|
pub fn serialize(&self) -> GenericArray<u8, CredentialResponseLen<CS>>
|
||||||
where
|
where
|
||||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||||
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
|
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
|
||||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
|
||||||
|
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
self.evaluation_element
|
<OprfGroup<CS> as Group>::serialize_elem(self.evaluation_element.value())
|
||||||
.value()
|
|
||||||
.to_arr()
|
|
||||||
.concat(self.masking_nonce)
|
.concat(self.masking_nonce)
|
||||||
.concat(self.masked_response.serialize())
|
.concat(self.masked_response.serialize())
|
||||||
.concat(self.ke2_message.to_bytes())
|
.concat(self.ke2_message.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn serialize_without_ke<'a>(
|
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>,
|
masking_nonce: &'a GenericArray<u8, NonceLen>,
|
||||||
masked_response: &'a MaskedResponse<CS>,
|
masked_response: &'a MaskedResponse<CS>,
|
||||||
) -> impl Iterator<Item = &'a [u8]> {
|
) -> impl Iterator<Item = &'a [u8]> {
|
||||||
@@ -459,12 +500,12 @@ where
|
|||||||
|
|
||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||||
let elem_len = <CS::OprfGroup as Group>::ElemLen::USIZE;
|
let elem_len = <OprfGroup<CS> as Group>::ElemLen::USIZE;
|
||||||
let key_len = <CS::KeGroup as KeGroup>::PkLen::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 envelope_len = Envelope::<CS>::len();
|
||||||
let masked_response_len = key_len + envelope_len;
|
let masked_response_len = key_len + envelope_len;
|
||||||
let ke2_message_len = CS::KeyExchange::ke2_message_size();
|
let ke2_message_len = Ke2MessageLen::<CS>::USIZE;
|
||||||
|
|
||||||
let checked_slice = check_slice_size_atleast(
|
let checked_slice = check_slice_size_atleast(
|
||||||
input,
|
input,
|
||||||
@@ -476,10 +517,11 @@ where
|
|||||||
// subgroup
|
// subgroup
|
||||||
let beta_bytes = &checked_slice[..elem_len];
|
let beta_bytes = &checked_slice[..elem_len];
|
||||||
let evaluation_element =
|
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
|
// 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);
|
return Err(ProtocolError::IdentityGroupElementError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,7 +531,7 @@ where
|
|||||||
&checked_slice[elem_len + nonce_len..elem_len + nonce_len + masked_response_len],
|
&checked_slice[elem_len + nonce_len..elem_len + nonce_len + masked_response_len],
|
||||||
);
|
);
|
||||||
let ke2_message =
|
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..],
|
&checked_slice[elem_len + nonce_len + masked_response_len..],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -504,7 +546,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Only used for tests, where we can set the beta value to test for the
|
/// Only used for tests, where we can set the beta value to test for the
|
||||||
/// reflection error case
|
/// 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 {
|
Self {
|
||||||
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
||||||
masking_nonce: self.masking_nonce,
|
masking_nonce: self.masking_nonce,
|
||||||
@@ -519,9 +561,12 @@ pub type CredentialFinalizationLen<CS: CipherSuite> = Ke3MessageLen<CS>;
|
|||||||
|
|
||||||
impl<CS: CipherSuite> CredentialFinalization<CS>
|
impl<CS: CipherSuite> CredentialFinalization<CS>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
/// Serialization into bytes
|
||||||
pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>> {
|
pub fn serialize(&self) -> GenericArray<u8, CredentialFinalizationLen<CS>> {
|
||||||
@@ -531,7 +576,9 @@ where
|
|||||||
/// Deserialization from bytes
|
/// Deserialization from bytes
|
||||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||||
let ke3_message =
|
let ke3_message =
|
||||||
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE3Message::from_bytes(input)?;
|
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE3Message::from_bytes(
|
||||||
|
input,
|
||||||
|
)?;
|
||||||
Ok(Self { ke3_message })
|
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 generic_array::{ArrayLength, GenericArray};
|
||||||
use hmac::Mac;
|
use hmac::Mac;
|
||||||
|
|
||||||
use crate::errors::ProtocolError;
|
use crate::errors::{InternalError, ProtocolError};
|
||||||
|
|
||||||
// Corresponds to the I2OSP() function from RFC8017
|
// Corresponds to the I2OSP() function from RFC8017
|
||||||
pub(crate) fn i2osp<L: ArrayLength<u8>>(
|
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)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
|||||||
Executable → Regular
+174
-123
@@ -10,8 +10,8 @@ use std::vec;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||||
use digest::Output;
|
use digest::{Output, OutputSizeUser};
|
||||||
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;
|
use generic_array::ArrayLength;
|
||||||
use proptest::collection::vec;
|
use proptest::collection::vec;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
@@ -19,16 +19,16 @@ use rand::rngs::OsRng;
|
|||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use voprf::Group;
|
use voprf::Group;
|
||||||
|
|
||||||
use crate::ciphersuite::CipherSuite;
|
use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
|
||||||
use crate::envelope::{Envelope, EnvelopeLen, InnerEnvelopeMode};
|
use crate::envelope::{Envelope, EnvelopeLen, InnerEnvelopeMode};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::hash::{OutputSize, ProxyHash};
|
use crate::hash::{Hash, OutputSize, ProxyHash};
|
||||||
use crate::key_exchange::group::KeGroup;
|
use crate::key_exchange::group::KeGroup;
|
||||||
use crate::key_exchange::traits::{
|
use crate::key_exchange::traits::{
|
||||||
FromBytes, Ke1MessageLen, Ke1StateLen, Ke2MessageLen, KeyExchange, ToBytes,
|
FromBytes, Ke1MessageLen, Ke1StateLen, Ke2MessageLen, KeyExchange, ToBytes,
|
||||||
};
|
};
|
||||||
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
|
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
|
||||||
use crate::keypair::KeyPair;
|
use crate::keypair::{KeyPair, SecretKey};
|
||||||
use crate::messages::CredentialResponseWithoutKeLen;
|
use crate::messages::CredentialResponseWithoutKeLen;
|
||||||
use crate::opaque::{ClientLoginLen, ClientRegistrationLen, MaskedResponseLen};
|
use crate::opaque::{ClientLoginLen, ClientRegistrationLen, MaskedResponseLen};
|
||||||
use crate::serialization::{i2osp, os2ip};
|
use crate::serialization::{i2osp, os2ip};
|
||||||
@@ -36,31 +36,32 @@ use crate::*;
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
struct Ristretto255;
|
struct Ristretto255;
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Ristretto255 {
|
impl CipherSuite for Ristretto255 {
|
||||||
type OprfGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type OprfGroup = crate::Ristretto255;
|
||||||
type KeGroup = curve25519_dalek::ristretto::RistrettoPoint;
|
type KeGroup = crate::Ristretto255;
|
||||||
type KeyExchange = TripleDH;
|
type KeyExchange = TripleDH;
|
||||||
type Hash = sha2::Sha512;
|
|
||||||
type SlowHash = crate::slow_hash::NoOpHash;
|
type SlowHash = crate::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
struct P256;
|
struct P256;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
impl CipherSuite for P256 {
|
impl CipherSuite for P256 {
|
||||||
type OprfGroup = p256_::ProjectivePoint;
|
type OprfGroup = ::p256::NistP256;
|
||||||
type KeGroup = p256_::PublicKey;
|
type KeGroup = ::p256::NistP256;
|
||||||
type KeyExchange = TripleDH;
|
type KeyExchange = TripleDH;
|
||||||
type Hash = sha2::Sha256;
|
|
||||||
type SlowHash = crate::slow_hash::NoOpHash;
|
type SlowHash = crate::slow_hash::NoOpHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_point<CS: CipherSuite>() -> CS::KeGroup
|
fn random_point<CS: CipherSuite>() -> <CS::KeGroup as KeGroup>::Pk
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 rng = OsRng;
|
||||||
let sk = CS::KeGroup::random_sk(&mut rng);
|
let sk = CS::KeGroup::random_sk(&mut rng);
|
||||||
@@ -71,18 +72,20 @@ where
|
|||||||
fn client_registration_roundtrip() -> Result<(), ProtocolError> {
|
fn client_registration_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// 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>,
|
ClientRegistrationLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let pw = b"hunter2";
|
let pw = b"hunter2";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
let blind_result =
|
let blind_result = &voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
|
||||||
&voprf::NonVerifiableClient::<CS::OprfGroup, CS::Hash>::blind(pw, &mut rng)?;
|
|
||||||
|
|
||||||
let bytes: Vec<u8> = blind_result
|
let bytes: Vec<u8> = blind_result
|
||||||
.state
|
.state
|
||||||
@@ -100,7 +103,6 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -110,22 +112,25 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn server_registration_roundtrip() -> Result<(), ProtocolError> {
|
fn server_registration_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
// ServerRegistration = RegistrationUpload
|
// ServerRegistration = RegistrationUpload
|
||||||
{
|
{
|
||||||
// If we don't have envelope and client_pk, the server registration just
|
// If we don't have envelope and client_pk, the server registration just
|
||||||
let mut rng = OsRng;
|
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);
|
rng.fill_bytes(&mut masking_key);
|
||||||
|
|
||||||
// Construct a mock envelope
|
// Construct a mock envelope
|
||||||
@@ -135,12 +140,12 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
// ciphertext which is an encrypted private key
|
// ciphertext which is an encrypted private key
|
||||||
//mock_envelope_bytes.extend_from_slice(&ciphertext);
|
//mock_envelope_bytes.extend_from_slice(&ciphertext);
|
||||||
// length-MAC_SIZE hmac
|
// 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);
|
let mock_client_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
||||||
// serialization order: oprf_key, public key, envelope
|
// serialization order: oprf_key, public key, envelope
|
||||||
let mut bytes = Vec::<u8>::new();
|
let mut bytes = Vec::<u8>::new();
|
||||||
bytes.extend_from_slice(&mock_client_kp.public().to_arr());
|
bytes.extend_from_slice(&mock_client_kp.public().to_bytes());
|
||||||
bytes.extend_from_slice(&masking_key);
|
bytes.extend_from_slice(&masking_key);
|
||||||
bytes.extend_from_slice(&mock_envelope_bytes);
|
bytes.extend_from_slice(&mock_envelope_bytes);
|
||||||
let reg = ServerRegistration::<CS>::deserialize(&bytes)?;
|
let reg = ServerRegistration::<CS>::deserialize(&bytes)?;
|
||||||
@@ -151,7 +156,6 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -161,12 +165,15 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn registration_request_roundtrip() -> Result<(), ProtocolError> {
|
fn registration_request_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 = random_point::<CS>();
|
||||||
let pt_bytes = pt.to_arr().to_vec();
|
let pt_bytes = CS::KeGroup::serialize_pk(&pt);
|
||||||
|
|
||||||
let mut input = Vec::new();
|
let mut input = Vec::new();
|
||||||
input.extend_from_slice(&pt_bytes);
|
input.extend_from_slice(&pt_bytes);
|
||||||
@@ -176,13 +183,13 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
assert_eq!(input, *r1_bytes);
|
assert_eq!(input, *r1_bytes);
|
||||||
|
|
||||||
// Assert that identity group element is rejected
|
// Assert that identity group element is rejected
|
||||||
let identity = CS::OprfGroup::identity();
|
let identity = OprfGroup::<CS>::identity_elem();
|
||||||
let identity_bytes = identity.to_arr().to_vec();
|
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
RegistrationRequest::<CS>::deserialize(&identity_bytes),
|
RegistrationRequest::<CS>::deserialize(&identity_bytes),
|
||||||
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
||||||
voprf::Error::PointError,
|
voprf::Error::Deserialization,
|
||||||
)))
|
)))
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -191,7 +198,6 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -201,18 +207,21 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// 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>,
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let pt = random_point::<CS>();
|
let pt = random_point::<CS>();
|
||||||
let beta_bytes = pt.to_arr();
|
let beta_bytes = CS::KeGroup::serialize_pk(&pt);
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
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();
|
let mut input = Vec::new();
|
||||||
input.extend_from_slice(&beta_bytes);
|
input.extend_from_slice(&beta_bytes);
|
||||||
@@ -223,15 +232,15 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
assert_eq!(input, *r2_bytes);
|
assert_eq!(input, *r2_bytes);
|
||||||
|
|
||||||
// Assert that identity group element is rejected
|
// Assert that identity group element is rejected
|
||||||
let identity = CS::OprfGroup::identity();
|
let identity = OprfGroup::<CS>::identity_elem();
|
||||||
let identity_bytes = identity.to_arr().to_vec();
|
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
RegistrationResponse::<CS>::deserialize(
|
RegistrationResponse::<CS>::deserialize(
|
||||||
&[identity_bytes, pubkey_bytes.to_vec()].concat()
|
&[identity_bytes, pubkey_bytes.to_vec()].concat()
|
||||||
),
|
),
|
||||||
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
||||||
voprf::Error::PointError,
|
voprf::Error::Deserialization,
|
||||||
)))
|
)))
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -240,7 +249,6 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -250,28 +258,31 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let skp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
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];
|
let mut key = [0u8; 32];
|
||||||
rng.fill_bytes(&mut key);
|
rng.fill_bytes(&mut key);
|
||||||
let mut nonce = [0u8; NonceLen::USIZE];
|
let mut nonce = [0u8; NonceLen::USIZE];
|
||||||
rng.fill_bytes(&mut nonce);
|
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);
|
rng.fill_bytes(&mut masking_key);
|
||||||
|
|
||||||
let randomized_pwd_hasher = hkdf::Hkdf::new(None, &key);
|
let randomized_pwd_hasher = hkdf::Hkdf::new(None, &key);
|
||||||
@@ -299,7 +310,6 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -309,22 +319,29 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn credential_request_roundtrip() -> Result<(), ProtocolError> {
|
fn credential_request_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// CredentialRequest: KgPk + Ke1Message
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let alpha = random_point::<CS>();
|
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 client_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
||||||
let mut client_nonce = [0u8; NonceLen::USIZE];
|
let mut client_nonce = [0u8; NonceLen::USIZE];
|
||||||
rng.fill_bytes(&mut client_nonce);
|
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();
|
let mut input = Vec::new();
|
||||||
input.extend_from_slice(&alpha_bytes);
|
input.extend_from_slice(&alpha_bytes);
|
||||||
@@ -335,13 +352,13 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
assert_eq!(input, *l1_bytes);
|
assert_eq!(input, *l1_bytes);
|
||||||
|
|
||||||
// Assert that identity group element is rejected
|
// Assert that identity group element is rejected
|
||||||
let identity = CS::OprfGroup::identity();
|
let identity = OprfGroup::<CS>::identity_elem();
|
||||||
let identity_bytes = identity.to_arr().to_vec();
|
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
CredentialRequest::<CS>::deserialize(&[identity_bytes, ke1m.to_vec()].concat()),
|
CredentialRequest::<CS>::deserialize(&[identity_bytes, ke1m.to_vec()].concat()),
|
||||||
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
||||||
voprf::Error::PointError,
|
voprf::Error::Deserialization,
|
||||||
)))
|
)))
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -350,7 +367,6 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -360,24 +376,28 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||||
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>:
|
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>:
|
||||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>:
|
||||||
|
ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
let pt = random_point::<CS>();
|
let pt = random_point::<CS>();
|
||||||
let pt_bytes = pt.to_arr();
|
let pt_bytes = CS::KeGroup::serialize_pk(&pt);
|
||||||
|
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
@@ -385,16 +405,21 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
rng.fill_bytes(&mut masking_nonce);
|
rng.fill_bytes(&mut masking_nonce);
|
||||||
|
|
||||||
let mut masked_response =
|
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);
|
rng.fill_bytes(&mut masked_response);
|
||||||
|
|
||||||
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
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);
|
rng.fill_bytes(&mut mac);
|
||||||
let mut server_nonce = [0u8; NonceLen::USIZE];
|
let mut server_nonce = [0u8; NonceLen::USIZE];
|
||||||
rng.fill_bytes(&mut server_nonce);
|
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();
|
let mut input = Vec::new();
|
||||||
input.extend_from_slice(&pt_bytes);
|
input.extend_from_slice(&pt_bytes);
|
||||||
@@ -407,8 +432,8 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
assert_eq!(input, *l2_bytes);
|
assert_eq!(input, *l2_bytes);
|
||||||
|
|
||||||
// Assert that identity group element is rejected
|
// Assert that identity group element is rejected
|
||||||
let identity = CS::OprfGroup::identity();
|
let identity = OprfGroup::<CS>::identity_elem();
|
||||||
let identity_bytes = identity.to_arr().to_vec();
|
let identity_bytes = OprfGroup::<CS>::serialize_elem(identity).to_vec();
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
CredentialResponse::<CS>::deserialize(
|
CredentialResponse::<CS>::deserialize(
|
||||||
@@ -421,7 +446,7 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
.concat()
|
.concat()
|
||||||
),
|
),
|
||||||
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
Err(ProtocolError::LibraryError(InternalError::OprfError(
|
||||||
voprf::Error::PointError,
|
voprf::Error::Deserialization,
|
||||||
)))
|
)))
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -430,7 +455,6 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -440,12 +464,15 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
|
fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 rng = OsRng;
|
||||||
let mut mac = Output::<CS::Hash>::default();
|
let mut mac = Output::<OprfHash<CS>>::default();
|
||||||
rng.fill_bytes(&mut mac);
|
rng.fill_bytes(&mut mac);
|
||||||
|
|
||||||
let input = mac;
|
let input = mac;
|
||||||
@@ -459,7 +486,6 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -469,15 +495,18 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn client_login_roundtrip() -> Result<(), ProtocolError> {
|
fn client_login_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// CredentialRequest: KgPk + Ke1Message
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||||
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
||||||
<CS::OprfGroup as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
<OprfGroup<CS> as Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
||||||
Sum<<CS::OprfGroup as Group>::ScalarLen, CredentialRequestLen<CS>>:
|
Sum<<OprfGroup<CS> as Group>::ScalarLen, CredentialRequestLen<CS>>:
|
||||||
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
||||||
ClientLoginLen<CS>: ArrayLength<u8>,
|
ClientLoginLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
@@ -489,19 +518,22 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
rng.fill_bytes(&mut client_nonce);
|
rng.fill_bytes(&mut client_nonce);
|
||||||
|
|
||||||
let l1_data = [
|
let l1_data = [
|
||||||
client_e_kp.private().to_arr().to_vec(),
|
client_e_kp.private().serialize().to_vec(),
|
||||||
client_nonce.to_vec(),
|
client_nonce.to_vec(),
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
|
|
||||||
let blind_result =
|
let blind_result = voprf::NonVerifiableClient::<CS::OprfGroup>::blind(pw, &mut rng)?;
|
||||||
voprf::NonVerifiableClient::<CS::OprfGroup, CS::Hash>::blind(pw, &mut rng)?;
|
|
||||||
|
|
||||||
let credential_request = CredentialRequest::<CS> {
|
let credential_request = CredentialRequest::<CS> {
|
||||||
blinded_element: blind_result.message,
|
blinded_element: blind_result.message,
|
||||||
ke1_message:
|
ke1_message:
|
||||||
<CS::KeyExchange as KeyExchange<CS::Hash, CS::KeGroup>>::KE1Message::from_bytes(
|
<CS::KeyExchange as KeyExchange<OprfHash<CS>, CS::KeGroup>>::KE1Message::from_bytes(
|
||||||
&[client_nonce.as_ref(), client_e_kp.public()].concat(),
|
&[
|
||||||
|
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")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -531,9 +562,12 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 rng = OsRng;
|
||||||
|
|
||||||
@@ -541,9 +575,15 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
let mut client_nonce = vec![0u8; NonceLen::USIZE];
|
let mut client_nonce = vec![0u8; NonceLen::USIZE];
|
||||||
rng.fill_bytes(&mut client_nonce);
|
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 =
|
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();
|
let reg_bytes = reg.to_bytes();
|
||||||
assert_eq!(*reg_bytes, ke1m);
|
assert_eq!(*reg_bytes, ke1m);
|
||||||
|
|
||||||
@@ -552,7 +592,6 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -562,22 +601,32 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 rng = OsRng;
|
||||||
|
|
||||||
let server_e_kp = KeyPair::<CS::KeGroup>::generate_random(&mut rng);
|
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);
|
rng.fill_bytes(&mut mac);
|
||||||
let mut server_nonce = vec![0u8; NonceLen::USIZE];
|
let mut server_nonce = vec![0u8; NonceLen::USIZE];
|
||||||
rng.fill_bytes(&mut server_nonce);
|
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 =
|
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();
|
let reg_bytes = reg.to_bytes();
|
||||||
assert_eq!(*reg_bytes, ke2m);
|
assert_eq!(*reg_bytes, ke2m);
|
||||||
|
|
||||||
@@ -586,7 +635,6 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -596,18 +644,23 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
fn ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
fn ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
||||||
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
fn inner<CS: CipherSuite>() -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 rng = OsRng;
|
||||||
let mut mac = Output::<CS::Hash>::default();
|
let mut mac = Output::<OprfHash<CS>>::default();
|
||||||
rng.fill_bytes(&mut mac);
|
rng.fill_bytes(&mut mac);
|
||||||
|
|
||||||
let ke3m: Vec<u8> = [mac].concat();
|
let ke3m: Vec<u8> = [mac].concat();
|
||||||
|
|
||||||
let reg =
|
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();
|
let reg_bytes = reg.to_bytes();
|
||||||
assert_eq!(*reg_bytes, ke3m);
|
assert_eq!(*reg_bytes, ke3m);
|
||||||
|
|
||||||
@@ -616,7 +669,6 @@ fn ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
inner::<Ristretto255>()?;
|
inner::<Ristretto255>()?;
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
inner::<P256>()?;
|
inner::<P256>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -707,5 +759,4 @@ macro_rules! test {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
test!(ristretto255, Ristretto255);
|
test!(ristretto255, Ristretto255);
|
||||||
#[cfg(feature = "p256")]
|
|
||||||
test!(p256, P256);
|
test!(p256, P256);
|
||||||
|
|||||||
+17
-26
@@ -7,48 +7,39 @@
|
|||||||
|
|
||||||
//! Trait specifying a slow hashing function
|
//! Trait specifying a slow hashing function
|
||||||
|
|
||||||
use digest::core_api::BlockSizeUser;
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use digest::Output;
|
|
||||||
use generic_array::typenum::{IsLess, Le, NonZero, U256};
|
|
||||||
|
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
use crate::hash::{Hash, ProxyHash};
|
|
||||||
|
|
||||||
/// Used for the slow hashing function in OPAQUE
|
/// Used for the slow hashing function in OPAQUE
|
||||||
pub trait SlowHash<D: Hash>: Default
|
pub trait SlowHash: Default {
|
||||||
where
|
|
||||||
D::Core: ProxyHash,
|
|
||||||
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
|
||||||
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
|
||||||
{
|
|
||||||
/// Computes the slow hashing function
|
/// 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
|
/// A no-op hash which simply returns its input
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct NoOpHash;
|
pub struct NoOpHash;
|
||||||
|
|
||||||
impl<D: Hash> SlowHash<D> for NoOpHash
|
impl SlowHash for NoOpHash {
|
||||||
where
|
fn hash<L: ArrayLength<u8>>(
|
||||||
D::Core: ProxyHash,
|
&self,
|
||||||
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
input: GenericArray<u8, L>,
|
||||||
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
) -> Result<GenericArray<u8, L>, InternalError> {
|
||||||
{
|
|
||||||
fn hash(&self, input: Output<D>) -> Result<Output<D>, InternalError> {
|
|
||||||
Ok(input)
|
Ok(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "slow-hash")]
|
#[cfg(feature = "slow-hash")]
|
||||||
impl<D: Hash> SlowHash<D> for argon2::Argon2<'_>
|
impl SlowHash for argon2::Argon2<'_> {
|
||||||
where
|
fn hash<L: ArrayLength<u8>>(
|
||||||
D::Core: ProxyHash,
|
&self,
|
||||||
<D::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
input: GenericArray<u8, L>,
|
||||||
Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
) -> Result<GenericArray<u8, L>, InternalError> {
|
||||||
{
|
let mut output = GenericArray::default();
|
||||||
fn hash(&self, input: Output<D>) -> Result<Output<D>, InternalError> {
|
|
||||||
let mut output = Output::<D>::default();
|
|
||||||
self.hash_password_into(&input, &[0; argon2::MIN_SALT_LEN], &mut output)
|
self.hash_password_into(&input, &[0; argon2::MIN_SALT_LEN], &mut output)
|
||||||
.map_err(|_| InternalError::SlowHashError)?;
|
.map_err(|_| InternalError::SlowHashError)?;
|
||||||
Ok(output)
|
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.
|
// of this source tree.
|
||||||
|
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
use std::string::ToString;
|
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use std::{println, vec};
|
use std::{println, vec};
|
||||||
|
|
||||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
use digest::OutputSizeUser;
|
||||||
use generic_array::ArrayLength;
|
use generic_array::typenum::{IsLess, IsLessOrEqual, Le, NonZero, Sum, U256};
|
||||||
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
|
use rand::rngs::OsRng;
|
||||||
|
use rand::RngCore;
|
||||||
use voprf::Group;
|
use voprf::Group;
|
||||||
|
|
||||||
use crate::ciphersuite::CipherSuite;
|
use crate::ciphersuite::{CipherSuite, OprfGroup, OprfHash};
|
||||||
use crate::envelope::EnvelopeLen;
|
use crate::envelope::EnvelopeLen;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::hash::{OutputSize, ProxyHash};
|
use crate::hash::{Hash, OutputSize, ProxyHash};
|
||||||
use crate::key_exchange::group::KeGroup;
|
use crate::key_exchange::group::KeGroup;
|
||||||
use crate::key_exchange::traits::{Ke1MessageLen, Ke2MessageLen};
|
use crate::key_exchange::traits::{Ke1MessageLen, Ke2MessageLen};
|
||||||
use crate::key_exchange::tripledh::{NonceLen, TripleDH};
|
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>> {
|
fn decode(values: &JsonValue, key: &str) -> Option<Vec<u8>> {
|
||||||
values[key]
|
values[key].as_str().and_then(|s| hex::decode(&s).ok())
|
||||||
.as_str()
|
|
||||||
.and_then(|s| hex::decode(&s.to_string()).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 {
|
OpaqueTestVectorParameters {
|
||||||
dummy_private_key: parse_default_random!(values, "client_private_key", 32),
|
dummy_private_key: {
|
||||||
dummy_masking_key: parse_default_random!(values, "masking_key", 64),
|
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"),
|
context: parse!(values, "Context"),
|
||||||
client_private_key: decode(values, "client_private_key"),
|
client_private_key: decode(values, "client_private_key"),
|
||||||
client_keyshare: parse!(values, "client_keyshare"),
|
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>
|
fn get_password_file_bytes<CS: CipherSuite>(parameters: &OpaqueTestVectorParameters) -> Vec<u8>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
// ServerRegistration = RegistrationUpload
|
// ServerRegistration = RegistrationUpload
|
||||||
@@ -174,12 +188,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! json_to_test_vectors {
|
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]
|
$v[$vector_type]
|
||||||
.members()
|
.members()
|
||||||
.filter_map(|x| {
|
.filter_map(|x| {
|
||||||
if x.has_key($cs) {
|
if x.has_key($cs) {
|
||||||
Some(populate_test_vectors(&x[$cs]))
|
Some(populate_test_vectors::<$cs_ty>(&x[$cs]))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -195,24 +209,33 @@ fn tests() -> Result<(), ProtocolError> {
|
|||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[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!(
|
assert!(
|
||||||
!(ristretto_real_tvs.is_empty() || ristretto_fake_tvs.is_empty()),
|
!(ristretto_real_tvs.is_empty() || ristretto_fake_tvs.is_empty()),
|
||||||
"Parsing error"
|
"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_request::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
|
||||||
test_registration_response::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
|
test_registration_response::<Ristretto255Sha512NoSlowHash>(&ristretto_real_tvs)?;
|
||||||
test_registration_upload::<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)?;
|
test_fake_vectors::<Ristretto255Sha512NoSlowHash>(&ristretto_fake_tvs)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "p256")]
|
struct P256Sha256NoSlowHash;
|
||||||
{
|
impl CipherSuite for P256Sha256NoSlowHash {
|
||||||
let p256_real_tvs =
|
type OprfGroup = p256::NistP256;
|
||||||
json_to_test_vectors!(rfc, "Real", "P256_XMD:SHA-256_SSWU_RO_, SHA256",);
|
type KeGroup = p256::NistP256;
|
||||||
let p256_fake_tvs =
|
type KeyExchange = TripleDH;
|
||||||
json_to_test_vectors!(rfc, "Fake", "P256_XMD:SHA-256_SSWU_RO_, SHA256",);
|
type SlowHash = NoOpHash;
|
||||||
|
|
||||||
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)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,9 +288,12 @@ fn test_registration_request<CS: CipherSuite>(
|
|||||||
tvs: &[OpaqueTestVectorParameters],
|
tvs: &[OpaqueTestVectorParameters],
|
||||||
) -> Result<(), ProtocolError>
|
) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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 {
|
for parameters in tvs {
|
||||||
let mut rng = CycleRng::new(parameters.blind_registration.to_vec());
|
let mut rng = CycleRng::new(parameters.blind_registration.to_vec());
|
||||||
@@ -281,11 +311,14 @@ fn test_registration_response<CS: CipherSuite>(
|
|||||||
tvs: &[OpaqueTestVectorParameters],
|
tvs: &[OpaqueTestVectorParameters],
|
||||||
) -> Result<(), ProtocolError>
|
) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// 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>,
|
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
@@ -318,15 +351,18 @@ fn test_registration_upload<CS: CipherSuite>(
|
|||||||
tvs: &[OpaqueTestVectorParameters],
|
tvs: &[OpaqueTestVectorParameters],
|
||||||
) -> Result<(), ProtocolError>
|
) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
@@ -362,7 +398,7 @@ where
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(¶meters.export_key),
|
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>
|
fn test_ke1<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// CredentialRequest: KgPk + Ke1Message
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
@@ -404,29 +443,32 @@ where
|
|||||||
|
|
||||||
fn test_ke2<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
fn test_ke2<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
// ServerRegistration = RegistrationUpload
|
// ServerRegistration = RegistrationUpload
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||||
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||||
@@ -489,12 +531,15 @@ where
|
|||||||
|
|
||||||
fn test_ke3<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
fn test_ke3<CS: CipherSuite>(tvs: &[OpaqueTestVectorParameters]) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
@@ -549,21 +594,24 @@ fn test_server_login_finish<CS: CipherSuite>(
|
|||||||
tvs: &[OpaqueTestVectorParameters],
|
tvs: &[OpaqueTestVectorParameters],
|
||||||
) -> Result<(), ProtocolError>
|
) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// Envelope: Nonce + Hash
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
EnvelopeLen<CS>: ArrayLength<u8>,
|
EnvelopeLen<CS>: ArrayLength<u8>,
|
||||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||||
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<CS::Hash>>,
|
<CS::KeGroup as KeGroup>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<CS::Hash>>:
|
Sum<<CS::KeGroup as KeGroup>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||||
// ServerRegistration = RegistrationUpload
|
// ServerRegistration = RegistrationUpload
|
||||||
// MaskedResponse: (Nonce + Hash) + KePk
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
@@ -618,16 +666,19 @@ fn test_fake_vectors<CS: CipherSuite>(
|
|||||||
tvs: &[OpaqueTestVectorParameters],
|
tvs: &[OpaqueTestVectorParameters],
|
||||||
) -> Result<(), ProtocolError>
|
) -> Result<(), ProtocolError>
|
||||||
where
|
where
|
||||||
<CS::Hash as CoreProxy>::Core: ProxyHash,
|
<OprfHash<CS> as OutputSizeUser>::OutputSize:
|
||||||
<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
IsLess<U256> + IsLessOrEqual<<OprfHash<CS> as BlockSizeUser>::BlockSize>,
|
||||||
Le<<<CS::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
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
|
// MaskedResponse: (Nonce + Hash) + KePk
|
||||||
NonceLen: Add<OutputSize<CS::Hash>>,
|
NonceLen: Add<OutputSize<OprfHash<CS>>>,
|
||||||
Sum<NonceLen, OutputSize<CS::Hash>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
Sum<NonceLen, OutputSize<OprfHash<CS>>>: ArrayLength<u8> + Add<<CS::KeGroup as KeGroup>::PkLen>,
|
||||||
MaskedResponseLen<CS>: ArrayLength<u8>,
|
MaskedResponseLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||||
<CS::OprfGroup as Group>::ElemLen: Add<NonceLen>,
|
<OprfGroup<CS> as Group>::ElemLen: Add<NonceLen>,
|
||||||
Sum<<CS::OprfGroup as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
Sum<<OprfGroup<CS> as Group>::ElemLen, NonceLen>: ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
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