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

Upgrade all core cryptographic dependencies to their latest versions:

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

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

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

Reviewed-on: #1
Co-authored-by: UneBaguette <[email protected]>
Co-committed-by: UneBaguette <[email protected]>
This commit was merged in pull request #1.
This commit is contained in:
2026-07-01 11:52:12 +02:00
committed by breakingbread
parent 5e2ba86643
commit 71df1ee49a
45 changed files with 1680 additions and 1483 deletions
+156
View File
@@ -0,0 +1,156 @@
name: Rust CI
on:
push:
branches:
- master
pull_request:
types: [ opened, reopened, synchronize ]
concurrency:
group: ci-${{ gitea.ref }}
cancel-in-progress: true
jobs:
fmt:
name: cargo fmt
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- name: Run cargo fmt
run: cargo fmt --all -- --check
clippy:
name: cargo clippy
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Cache cargo
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: cargo-registry-
- name: Run cargo clippy
run: cargo clippy --all-targets --features argon2,std,curve25519,ecdsa,ed25519,kem -- -D warnings
- name: Run cargo doc
run: cargo doc --no-deps --document-private-items --features argon2,std,curve25519,ecdsa,ed25519,kem
env:
RUSTDOCFLAGS: -D warnings
test:
name: test (${{ matrix.toolchain }} / ${{ matrix.backend_feature || 'no backend' }} / ${{ matrix.frontend_feature || 'no frontend' }})
runs-on: linux_amd64
strategy:
fail-fast: false
matrix:
backend_feature:
- ""
- --features ristretto255
- --features ristretto255,kem
- --features curve25519
- --features ecdsa
- --features ed25519
- --features ristretto255,curve25519,ecdsa,ed25519
frontend_feature:
- ""
- --features argon2
- --features serde
toolchain:
- stable
- "1.90.0"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@${{ matrix.toolchain }}
- name: Cache cargo
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: cargo-registry-
- name: Run cargo test
run: cargo test --no-default-features ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }}
- name: Run cargo test with std
run: cargo test --no-default-features --features std ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }}
simple-login-test:
name: test simple_login example
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
- name: Run expect
run: expect -f scripts/simple_login.exp
digital-locker-test:
name: test digital_locker example
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
- name: Run expect
run: expect -f scripts/digital_locker.exp
build-no-std:
name: no-std (${{ matrix.target }} / ${{ matrix.backend_feature || 'no backend' }})
runs-on: linux_amd64
strategy:
fail-fast: false
matrix:
target:
- wasm32-unknown-unknown
- thumbv6m-none-eabi
backend_feature:
- ""
- ristretto255
- curve25519
- ecdsa
- ed25519
- ristretto255,curve25519,ecdsa,ed25519
frontend_feature:
- argon2
- serde
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build no-std
run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }},${{ matrix.backend_feature }}
benches:
name: cargo bench compilation
runs-on: linux_amd64
strategy:
fail-fast: false
matrix:
backend_feature:
- --features ristretto255
- --features ristretto255,kem
- ""
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
- name: Run cargo bench --no-run
run: cargo bench --no-default-features ${{ matrix.backend_feature }} --no-run
audit:
name: cargo audit
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run cargo audit
run: cargo audit -D warnings
+26
View File
@@ -0,0 +1,26 @@
name: Publish
on:
release:
types: [ published ]
jobs:
publish:
runs-on: linux_amd64
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- uses: dtolnay/rust-toolchain@stable
- name: Login to crates.io
run: cargo login $CRATES_IO_TOKEN
env:
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
- name: Dry run publish
run: cargo publish --dry-run --manifest-path Cargo.toml
- name: Publish
run: cargo publish --manifest-path Cargo.toml
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
+81 -35
View File
@@ -1,67 +1,112 @@
# Changelog # Changelog
## 1.0.0-pre.0 (June 29, 2026)
Forked from [facebook/opaque-ke](https://github.com/facebook/opaque-ke/) at `4.1.0-pre.2`.
* Upgraded dependencies:
* `ml-kem`: `0.3.0-rc.0` to `0.3`
* `digest`: `0.10` to `0.11`
* `elliptic-curve`: `0.13` to `0.14`
* `curve25519-dalek`: `4` to `5.0.0-rc`
* `ed25519-dalek`: `2` to `3.0.0-rc`
* `ecdsa`: `0.16` to `0.17.0-rc.23`
* `hkdf`: `0.12` to `0.13`
* `hmac`: `0.12` to `0.13`
* `rand`: `0.8` to `0.10`
* `rand_chacha`: `0.3` to `0.10`
* `rfc6979`: `0.4` to `0.6` (now internal to `ecdsa`)
* `sha2`: `0.10` to `0.11`
* `getrandom`: `0.2` to `0.4` (WASM target)
* `p256`/`p384`/`p521`: `0.13` to `0.14.0-rc.15` (dev-dependency)
* `cryptoki`: `0.9` to `0.12` (dev-dependency)
* `rustyline`: `17` to `18` (dev-dependency)
* `scrypt`: `0.11` to `0.12` (dev-dependency)
* `voprf` replaced by `voprf-vx 1.0.0-pre.0`
* Bump `generic-array 0.14` to `generic-array 1.4` with `hybrid-array 0.4` interop
* Added `hybrid-array 0.4` for interop
* Added `ConcatExt` trait to disambiguate from `[T]::concat`
* Added **`cryptography`** to `categories` in `Cargo.toml`
* Replaced `Hmac` with `SimpleHmac` throughout for `digest 0.11` compatibility
* Replaced `bincode` with `postcard` for `no_std` serialization
* Re-exported `hybrid_array` from crate root
* Updated `Hash` trait to remove `BlockSizeUser` bounds incompatible with `digest 0.11`
* Updated `GroupEncoding Repr` bound to `hybrid_array::Array`
* Fixed `MaskedResponse::serialize` field ordering to match deserialization
* Increased **MSRV** to **1.90**
* Renamed crate to `opaque-vx`
* Removed direct `rfc6979` dependency (handled by `ecdsa` internally)
* Removed unstable `rustfmt` configurations for **Rust stable** compatibility
* Removed Facebook-specific contributions (CLA, bounty program) from `CONTRIBUTING.md`
* Removed `v3` to `v4` migration test (no longer relevant for fork)
## 4.1.0-pre.2 (March 26, 2026) ## 4.1.0-pre.2 (March 26, 2026)
* Upgraded ml-kem from 0.2 to 0.3.0-rc.0 * Upgraded ml-kem from 0.2 to 0.3.0-rc.0
* Increased MSRV to 1.87 * Increased MSRV to 1.87
## 4.1.0-pre.1 (November 17, 2025) ## 4.1.0-pre.1 (November 17, 2025)
* Added ml-kem re-export behind the kem feature * Added ml-kem re-export behind the kem feature
## 4.1.0-pre.0 (November 11, 2025) ## 4.1.0-pre.0 (November 11, 2025)
* Fixed dependency exporting for the rand crate * Fixed dependency exporting for the rand crate
* Added TripleDhKem key exchange protocol * Added TripleDhKem key exchange protocol
## 4.0.1 (October 30, 2025) ## 4.0.1 (October 30, 2025)
* Fixing docs building issue * Fixing docs building issue
## 4.0.0 (October 23, 2025) ## 4.0.0 (October 23, 2025)
* Increased MSRV to 1.83 * Increased MSRV to 1.83
* Synced implementation with RFC 9807 (no core protocol changes) * Synced implementation with RFC 9807 (no core protocol changes)
* Added a SIGMA-I key exchange implementation * Added a SIGMA-I key exchange implementation
* Removed KeGroup type from the Ciphersuite trait (now part of KeyExchange type) * Removed KeGroup type from the Ciphersuite trait (now part of KeyExchange type)
* **Breaking: existing Ciphersuite trait definitions need to be updated** * **Breaking: existing Ciphersuite trait definitions need to be updated**
* Ensured that dummy record is always created to avoid timing attack issues * Ensured that dummy record is always created to avoid timing attack issues
* Modified the dummy registration file to only contain the public key * Modified the dummy registration file to only contain the public key
instead of the keypair instead of the keypair
* **Breaking: existing `ServerSetup`s need to be updated** * **Breaking: existing `ServerSetup`s need to be updated**
```rust ```rust
// Given `old` is a `ServerSetup` from `opaque-ke` v3. // Given `old` is a `ServerSetup` from `opaque-ke` v3.
let old_serialized = old.serialize(); let old_serialized = old.serialize();
type OldSeedLen = <<<OldCipherSuite as opaque_ke_3::CipherSuite>::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; type OldSeedLen = <<<OldCipherSuite as opaque_ke_3::CipherSuite>::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize;
type OldSkLen = <<OldCipherSuite as opaque_ke_3::CipherSuite>::KeGroup as opaque_ke_3::key_exchange::group::KeGroup>::SkLen; type OldSkLen = <<OldCipherSuite as opaque_ke_3::CipherSuite>::KeGroup as opaque_ke_3::key_exchange::group::KeGroup>::SkLen;
let (old_serialied_rest, old_fake_keypair_serialized): ( let (old_serialied_rest, old_fake_keypair_serialized): (
GenericArray<u8, Sum<OldSeedLen, OldSkLen>>, GenericArray<u8, Sum<OldSeedLen, OldSkLen>>,
_, _,
) = old_serialized.split(); ) = old_serialized.split();
let old_fake_keypair = let old_fake_keypair =
KeyPair::<<OldCipherSuite as opaque_ke_3::CipherSuite>::KeGroup>::from_private_key_slice( KeyPair::<<OldCipherSuite as opaque_ke_3::CipherSuite>::KeGroup>::from_private_key_slice(
&old_fake_keypair_serialized, &old_fake_keypair_serialized,
) )
.unwrap(); .unwrap();
let old_fake_pk_serialized = old_fake_keypair.public().serialize(); let old_fake_pk_serialized = old_fake_keypair.public().serialize();
let new_serialized = old_serialied_rest.concat(old_fake_pk_serialized); let new_serialized = old_serialied_rest.concat(old_fake_pk_serialized);
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to `OldCipherSuite`. // Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to `OldCipherSuite`.
ServerSetup::<NewCipherSuite>::deserialize(&new_serialized).unwrap() ServerSetup::<NewCipherSuite>::deserialize(&new_serialized).unwrap()
``` ```
* Added remote OPRF seed support * Added remote OPRF seed support
* Replace remote private key trait with a state machine, facilitating async support. * Replace remote private key trait with a state machine, facilitating async support.
* Serde de/serialization formats have been simplified * Serde de/serialization formats have been simplified
* **Breaking: existing `ServerRegistration`s may need to be updated** * **Breaking: existing `ServerRegistration`s may need to be updated**
```rust ```rust
// Given `old` is a `ServerRegistration` from `opaque-ke` v3. // Given `old` is a `ServerRegistration` from `opaque-ke` v3.
let old_serialized = old.serialize(); let old_serialized = old.serialize();
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to the old cipher suite. // Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to the old cipher suite.
ServerRegistration::<NewCipherSuite>::deserialize(&old_serialized).unwrap() ServerRegistration::<NewCipherSuite>::deserialize(&old_serialized).unwrap()
``` ```
## 3.0.0 (October 10, 2024) ## 3.0.0 (October 10, 2024)
* Synced implementation with draft-irtf-cfrg-opaque-16 * Synced implementation with draft-irtf-cfrg-opaque-16
* **Breaking: protocol context string changed from `RFCXXXX` to `OPAQUEv1-`** * **Breaking: protocol context string changed from `RFCXXXX` to `OPAQUEv1-`**
* Dropped unmaintained json crate in favor of serde_json * Dropped unmaintained json crate in favor of serde_json
* Updated dependencies * Updated dependencies
* Increased MSRV to 1.74 * Increased MSRV to 1.74
@@ -69,11 +114,12 @@
* Adjusted key generation logic to be in line with commit 727b9ac of * Adjusted key generation logic to be in line with commit 727b9ac of
https://github.com/cfrg/draft-irtf-cfrg-opaque https://github.com/cfrg/draft-irtf-cfrg-opaque
* Updated VOPRF to draft 19 * Updated VOPRF to draft 19
* **Breaking: backwards-incompatible changes introduced in OPRF protocol** * **Breaking: backwards-incompatible changes introduced in OPRF protocol**
* Added P384 testing support * Added P384 testing support
* Renaming of X25519 to Curve25519 * Renaming of X25519 to Curve25519
## 2.0.0 (September 21, 2022) ## 2.0.0 (September 21, 2022)
* Synced implementation with draft-irtf-cfrg-opaque-10 * Synced implementation with draft-irtf-cfrg-opaque-10
* Changed argon2 salt length to recommended value (16 bytes) * Changed argon2 salt length to recommended value (16 bytes)
* Fixed issue from 2.0.0-pre.2 not pinning voprf dependency correctly * Fixed issue from 2.0.0-pre.2 not pinning voprf dependency correctly
-76
View File
@@ -1,76 +0,0 @@
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
-19
View File
@@ -2,29 +2,10 @@
We want to make contributing to this project as easy and transparent as We want to make contributing to this project as easy and transparent as
possible. possible.
## Pull Requests
We actively welcome your pull requests.
1. Fork the repo and create your branch from `main`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. If you haven't already, complete the Contributor License Agreement ("CLA").
## Contributor License Agreement ("CLA")
In order to accept your pull request, we need you to submit a CLA. You only need
to do this once to work on any of Facebook's open source projects.
Complete your CLA here: <https://code.facebook.com/cla>
## Issues ## Issues
We use GitHub issues to track public bugs. Please ensure your description is We use GitHub issues to track public bugs. Please ensure your description is
clear and has sufficient instructions to be able to reproduce the issue. clear and has sufficient instructions to be able to reproduce the issue.
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.
## License ## License
By contributing to opaque-ke, you agree that your contributions will be By contributing to opaque-ke, you agree that your contributions will be
licensed under both the LICENSE-MIT and LICENSE-APACHE files in the root licensed under both the LICENSE-MIT and LICENSE-APACHE files in the root
+72 -66
View File
@@ -1,110 +1,116 @@
[package] [package]
authors = ["Kevin Lewi <[email protected]>", "François Garillot <[email protected]>"] authors = [
categories = ["no-std"] "VexaHub Developers",
"Kevin Lewi <[email protected]>",
"François Garillot <[email protected]>",
]
categories = ["no-std", "cryptography"]
description = "An implementation of the OPAQUE password-authenticated key exchange protocol" description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
edition = "2024" edition = "2024"
exclude = ["/src/tests/"] exclude = ["/src/tests/"]
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] keywords = ["cryptography", "opaque", "passwords", "authentication", "pake"]
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
name = "opaque-ke" name = "opaque-vx"
readme = "README.md" readme = "README.md"
repository = "https://github.com/facebook/opaque-ke" repository = "https://github.com/vexahub/opaque-vx"
rust-version = "1.87" rust-version = "1.90"
version = "4.1.0-pre.2" version = "1.0.0-pre.0"
[features] [features]
argon2 = ["dep:argon2"] argon2 = ["dep:argon2"]
curve25519 = ["dep:curve25519-dalek"] curve25519 = ["dep:curve25519-dalek"]
default = ["ristretto255", "serde"] default = ["ristretto255", "serde"]
ecdsa = ["dep:ecdsa", "dep:rfc6979"] ecdsa = ["dep:ecdsa"]
ed25519 = ["dep:curve25519-dalek", "dep:ed25519-dalek"] ed25519 = ["dep:curve25519-dalek", "dep:ed25519-dalek"]
kem = ["dep:ml-kem", "dep:rand_core_10"] kem = ["dep:ml-kem", "dep:rand_core"]
ristretto255 = ["dep:curve25519-dalek", "voprf/ristretto255-ciphersuite"] ristretto255 = ["dep:curve25519-dalek", "voprf/ristretto255-ciphersuite"]
serde = [ serde = [
"dep:serde", "dep:serde",
"curve25519-dalek?/serde", "curve25519-dalek?/serde",
"ecdsa?/serde", "ecdsa?/serde",
"ed25519-dalek?/serde", "ed25519-dalek?/serde",
"elliptic-curve/serde", "elliptic-curve/serde",
"generic-array/serde", "generic-array/serde",
"voprf/serde", "hybrid-array/serde",
"zeroize/serde", "voprf/serde",
"zeroize/serde",
] ]
std = ["dep:getrandom", "rand/std"] std = ["dep:getrandom", "rand/std"]
[dependencies] [dependencies]
argon2 = { version = "0.5", default-features = false, features = [ argon2 = { version = "0.6.0-rc", default-features = false, features = [
"alloc", "alloc",
], optional = true } ], optional = true }
curve25519-dalek = { version = "4", default-features = false, features = [ curve25519-dalek = { version = "5.0.0-rc", default-features = false, features = [
"zeroize", "zeroize",
], optional = true } ], optional = true }
derive-where = { version = "1.4", features = ["zeroize-on-drop"] } derive-where = { version = "1.6", features = ["zeroize-on-drop"] }
digest = "0.10" digest = { version = "0.11", features = ["zeroize"] }
displaydoc = { version = "0.2", default-features = false } displaydoc = { version = "0.2", default-features = false }
ecdsa = { version = "0.16", default-features = false, features = [ ecdsa = { version = "0.17.0-rc.23", default-features = false, features = [
"arithmetic", "algorithm",
"hazmat",
], optional = true } ], optional = true }
ed25519-dalek = { version = "2", default-features = false, features = [ ed25519-dalek = { version = "3.0.0-rc", default-features = false, features = [
"digest", "digest",
"hazmat", "hazmat",
], optional = true } ], optional = true }
elliptic-curve = { version = "0.13", features = ["hash2curve", "sec1"] } elliptic-curve = { version = "0.14", features = ["sec1"] }
generic-array = "=0.14.7" # pinned to avoid deprecation warnings generic-array = { version = "1.4", features = ["hybrid-array-0_4", "zeroize"] }
hkdf = "0.12" hybrid-array = { version = "0.4", features = ["extra-sizes", "zeroize"] }
hmac = "0.12" hkdf = "0.13"
ml-kem = { version = "0.3.0-rc.0", default-features = false, features = [ hmac = "0.13"
"zeroize", ml-kem = { version = "0.3", default-features = false, features = [
"zeroize",
], optional = true } ], optional = true }
rand = { version = "0.8", default-features = false } rand = { version = "0.10", default-features = false }
rand_core_10 = { package = "rand_core", version = "0.10", default-features = false, optional = true } rand_core = { version = "0.10", default-features = false, optional = true }
rfc6979 = { version = "0.4", optional = true }
serde = { version = "1", default-features = false, features = [ serde = { version = "1", default-features = false, features = [
"derive", "derive",
], optional = true } ], optional = true }
subtle = { version = "2.6", default-features = false } subtle = { version = "2.6", default-features = false }
voprf = { version = "0.5", default-features = false, features = ["danger"] } voprf = { package = "voprf-vx", version = "1.0.0-pre.0", default-features = false, features = [
zeroize = { version = "1.8", features = ["zeroize_derive"] } "danger",
] }
zeroize = { version = "1.9", features = ["zeroize_derive"] }
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = { version = "0.2", features = ["js"], optional = true } getrandom = { version = "0.4", features = ["wasm_js"], optional = true }
[dev-dependencies] [dev-dependencies]
anyhow = "1" anyhow = "1"
bincode = "1" bincode-next = { version = "3", features = ["serde", "alloc"] }
chacha20poly1305 = "0.10" chacha20poly1305 = "0.11"
criterion = "0.8" criterion = "0.8"
cryptoki = "0.9" cryptoki = "0.12"
elliptic-curve = { version = "0.13", features = ["alloc", "pkcs8"] } elliptic-curve = { version = "0.14", features = ["alloc", "pkcs8"] }
rand_core = { version = "0.10", default-features = false }
hex = "0.4" hex = "0.4"
opaque-ke-3 = { package = "opaque-ke", version = "=3.0.0" } p256 = { version = "0.14.0-rc.15", default-features = false, features = [
p256 = { version = "0.13", default-features = false, features = [ "ecdsa",
"ecdsa", "hash2curve",
"hash2curve", "pkcs8",
"pkcs8", "oprf",
"voprf",
] } ] }
p384 = { version = "0.13", default-features = false, features = [ p384 = { version = "0.14.0-rc.15", default-features = false, features = [
"hash2curve", "hash2curve",
"pkcs8", "pkcs8",
"voprf", "oprf",
] } ] }
p521 = { version = "0.13.3", default-features = false, features = [ p521 = { version = "0.14.0-rc.15", default-features = false, features = [
"hash2curve", "hash2curve",
"pkcs8", "pkcs8",
"voprf", "oprf",
] } ] }
paste = "1" pastey = "0.2"
proptest = "1" proptest = "1"
rand = "0.8" rand = "0.10"
rand_chacha = "0.3" rand_chacha = "0.10"
regex = "1" regex = "1"
sha2 = { version = "0.10", default-features = false } sha2 = { version = "0.11", default-features = false }
thiserror = "2" thiserror = "2"
# MSRV # MSRV
rustyline = "17" rustyline = "18"
scrypt = "0.11" scrypt = "0.12"
serde_json = "1" serde_json = "1"
[[bench]] [[bench]]
+35 -16
View File
@@ -1,20 +1,28 @@
## The OPAQUE key exchange protocol ![Build Status](https://github.com/facebook/opaque-ke/workflows/Rust%20CI/badge.svg) ## The OPAQUE key exchange protocol
[OPAQUE](https://eprint.iacr.org/2018/163.pdf) is an augmented password-authenticated key exchange protocol. It allows a client to authenticate to a server using a password, without ever having to expose the plaintext password to the server. [OPAQUE](https://eprint.iacr.org/2018/163.pdf) is an augmented password-authenticated key exchange protocol. It allows a
client to authenticate to a server using a password, without ever having to expose the plaintext password to the server.
This implementation is based on [RFC 9807](https://datatracker.ietf.org/doc/rfc9807/). This implementation is based on [RFC 9807](https://datatracker.ietf.org/doc/rfc9807/).
This is a fork of [facebook/opaque-ke](https://github.com/facebook/opaque-ke) maintained
by [VexaHub](https://github.com/vexahub), targeting the latest **RustCrypto ecosystem**.
Background Background
---------- ----------
Augmented Password Authenticated Key Exchange (aPAKE) protocols are designed to provide password authentication and mutually authenticated key exchange without relying on PKI (except during user/password registration) and without disclosing passwords to servers or other entities other than the client machine. Augmented Password Authenticated Key Exchange (aPAKE) protocols are designed to provide password authentication and
mutually authenticated key exchange without relying on PKI (except during user/password registration) and without
disclosing passwords to servers or other entities other than the client machine.
OPAQUE is a PKI-free aPAKE that is secure against pre-computation attacks and capable of using a secret salt. OPAQUE is a PKI-free aPAKE that is secure against pre-computation attacks and capable of using a secret salt.
Documentation Documentation
------------- -------------
The API can be found [here](https://docs.rs/opaque-ke/) along with an example for usage. More examples can be found in the [examples](./examples) directory. The API can be found [here](https://docs.rs/opaque-ke-vx/) along with an example for usage. More examples can be found
in
the [examples](./examples) directory.
Installation Installation
------------ ------------
@@ -22,41 +30,52 @@ Installation
Add the following line to the dependencies of your `Cargo.toml`: Add the following line to the dependencies of your `Cargo.toml`:
``` ```
opaque-ke = "4.1.0-pre.2" opaque-ke = { package = "opaque-ke-vx", version = "1.0.0-pre.0" }
``` ```
### Minimum Supported Rust Version ### Minimum Supported Rust Version
Rust **1.87** or higher. Rust **1.89** or higher.
Audit Audit
----- -----
This library was audited by NCC Group in June of 2021. The audit was sponsored by WhatsApp for its use in [enabling end-to-end encrypted backups](https://engineering.fb.com/2021/09/10/security/whatsapp-e2ee-backups/). This library was audited by NCC Group in June of 2021. The audit was sponsored by WhatsApp for its use
in [enabling end-to-end encrypted backups](https://engineering.fb.com/2021/09/10/security/whatsapp-e2ee-backups/).
The audit found issues in release `v0.5.0`, and the fixes were subsequently incorporated into release `v1.2.0`. See the [full audit report here](https://research.nccgroup.com/2021/12/13/public-report-whatsapp-opaque-ke-cryptographic-implementation-review/). The audit found issues in release `v0.5.0`, and the fixes were subsequently incorporated into release `v1.2.0`. See
the [full audit report here](https://research.nccgroup.com/2021/12/13/public-report-whatsapp-opaque-ke-cryptographic-implementation-review/).
Resources Resources
--------- ---------
- [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security - [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of
security
- [RFC 9807](https://datatracker.ietf.org/doc/rfc9807/), containing a detailed (byte-level) specification for OPAQUE - [RFC 9807](https://datatracker.ietf.org/doc/rfc9807/), containing a detailed (byte-level) specification for OPAQUE
- ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory blog post written by Matthew Green that covers OPAQUE - ["Let's talk about PAKE"](https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/), an introductory
blog post written by Matthew Green that covers OPAQUE
- [@serenity-kit/opaque](https://github.com/serenity-kit/opaque), a WebAssembly package for this library - [@serenity-kit/opaque](https://github.com/serenity-kit/opaque), a WebAssembly package for this library
- [opaque-wasm](https://github.com/marucjmar/opaque-wasm), a WebAssembly package for this library. A comparison between `@serenity-kit/opaque` and `opaque-wasm` can be found [here](https://opaque-documentation.netlify.app/docs/faq#how-does-it-compare-to-opaque-wasm) - [opaque-wasm](https://github.com/marucjmar/opaque-wasm), a WebAssembly package for this library. A comparison between
- [react-native-opaque](https://github.com/serenity-kit/react-native-opaque), a React Native package for this library matching the API of `@serenity-kit/opaque` `@serenity-kit/opaque` and `opaque-wasm` can be
found [here](https://opaque-documentation.netlify.app/docs/faq#how-does-it-compare-to-opaque-wasm)
- [react-native-opaque](https://github.com/serenity-kit/react-native-opaque), a React Native package for this library
matching the API of `@serenity-kit/opaque`
Contributors Contributors
------------ ------------
The authors of this code are Kevin Lewi This fork is maintained by [VexaHub](https://github.com/vexahub).
([@kevinlewi](https://github.com/kevinlewi)) and François Garillot ([@huitseeker](https://github.com/huitseeker)).
The original authors are Kevin Lewi ([@kevinlewi](https://github.com/kevinlewi)) and François
Garillot ([@huitseeker](https://github.com/huitseeker)).
To learn more about contributing to this project, [see this document](./CONTRIBUTING.md). To learn more about contributing to this project, [see this document](./CONTRIBUTING.md).
#### Acknowledgments #### Acknowledgments
Special thanks go to Hugo Krawczyk and Chris Wood for helping to clarify discrepancies and making suggestions for improving Special thanks go to Hugo Krawczyk and Chris Wood for helping to clarify discrepancies and making suggestions for
this implementation. Additional credit goes to @daxpedda for adding no_std support, p256 support, and making other general improving
this implementation. Additional credit goes to @daxpedda for adding no_std support, p256 support, and making other
general
improvements to the library. improvements to the library.
License License
+18 -17
View File
@@ -10,8 +10,9 @@
extern crate criterion; extern crate criterion;
use criterion::Criterion; use criterion::Criterion;
use opaque_ke::*; use opaque_vx::*;
use rand::rngs::OsRng; use rand::rngs::SysRng;
use rand_core::UnwrapErr;
#[cfg(feature = "ristretto255")] #[cfg(feature = "ristretto255")]
static SUFFIX: &str = "ristretto255"; static SUFFIX: &str = "ristretto255";
@@ -22,20 +23,20 @@ struct Default;
#[cfg(feature = "ristretto255")] #[cfg(feature = "ristretto255")]
impl CipherSuite for Default { impl CipherSuite for Default {
type OprfCs = opaque_ke::Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
type Ksf = opaque_ke::ksf::Identity; type Ksf = ksf::Identity;
} }
#[cfg(not(feature = "ristretto255"))] #[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default { impl CipherSuite for Default {
type OprfCs = p256::NistP256; type OprfCs = p256::NistP256;
type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
type Ksf = opaque_ke::ksf::Identity; type Ksf = ksf::Identity;
} }
fn server_setup(c: &mut Criterion) { fn server_setup(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
c.bench_function(&format!("server setup ({SUFFIX})"), move |b| { c.bench_function(&format!("server setup ({SUFFIX})"), move |b| {
b.iter(|| { b.iter(|| {
@@ -45,7 +46,7 @@ fn server_setup(c: &mut Criterion) {
} }
fn client_registration_start(c: &mut Criterion) { fn client_registration_start(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let password = b"password"; let password = b"password";
c.bench_function(&format!("client registration start ({SUFFIX})"), move |b| { c.bench_function(&format!("client registration start ({SUFFIX})"), move |b| {
@@ -56,7 +57,7 @@ fn client_registration_start(c: &mut Criterion) {
} }
fn server_registration_start(c: &mut Criterion) { fn server_registration_start(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -76,7 +77,7 @@ fn server_registration_start(c: &mut Criterion) {
} }
fn client_registration_finish(c: &mut Criterion) { fn client_registration_finish(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -109,7 +110,7 @@ fn client_registration_finish(c: &mut Criterion) {
} }
fn server_registration_finish(c: &mut Criterion) { fn server_registration_finish(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -142,7 +143,7 @@ fn server_registration_finish(c: &mut Criterion) {
} }
fn client_login_start(c: &mut Criterion) { fn client_login_start(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let password = b"password"; let password = b"password";
c.bench_function(&format!("client login start ({SUFFIX})"), move |b| { c.bench_function(&format!("client login start ({SUFFIX})"), move |b| {
@@ -153,7 +154,7 @@ fn client_login_start(c: &mut Criterion) {
} }
fn server_login_start_real(c: &mut Criterion) { fn server_login_start_real(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -193,7 +194,7 @@ fn server_login_start_real(c: &mut Criterion) {
} }
fn server_login_start_fake(c: &mut Criterion) { fn server_login_start_fake(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -215,7 +216,7 @@ fn server_login_start_fake(c: &mut Criterion) {
} }
fn client_login_finish(c: &mut Criterion) { fn client_login_finish(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
@@ -265,7 +266,7 @@ fn client_login_finish(c: &mut Criterion) {
} }
fn server_login_finish(c: &mut Criterion) { fn server_login_finish(c: &mut Criterion) {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let username = b"username"; let username = b"username";
let password = b"password"; let password = b"password";
let server_setup = ServerSetup::<Default>::new(&mut rng); let server_setup = ServerSetup::<Default>::new(&mut rng);
+23 -23
View File
@@ -30,16 +30,16 @@ use std::process::exit;
use chacha20poly1305::aead::{Aead, KeyInit}; use chacha20poly1305::aead::{Aead, KeyInit};
use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce};
use opaque_ke::ciphersuite::CipherSuite; use opaque_vx::ciphersuite::CipherSuite;
use opaque_ke::generic_array::GenericArray; use opaque_vx::rand::Rng;
use opaque_ke::rand::RngCore; use opaque_vx::rand::rngs::SysRng;
use opaque_ke::rand::rngs::OsRng; use opaque_vx::{
use opaque_ke::{
ClientLogin, ClientLoginFinishParameters, ClientRegistration, ClientLogin, ClientLoginFinishParameters, ClientRegistration,
ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest, ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest,
CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin, CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin,
ServerLoginParameters, ServerRegistration, ServerRegistrationLen, ServerSetup, ServerLoginParameters, ServerRegistration, ServerSetup,
}; };
use rand_core::UnwrapErr;
use rustyline::Editor; use rustyline::Editor;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::history::DefaultHistory; use rustyline::history::DefaultHistory;
@@ -51,43 +51,43 @@ struct DefaultCipherSuite;
#[cfg(feature = "ristretto255")] #[cfg(feature = "ristretto255")]
impl CipherSuite for DefaultCipherSuite { impl CipherSuite for DefaultCipherSuite {
type OprfCs = opaque_ke::Ristretto255; type OprfCs = opaque_vx::Ristretto255;
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
type Ksf = opaque_ke::ksf::Identity; type Ksf = opaque_vx::ksf::Identity;
} }
#[cfg(not(feature = "ristretto255"))] #[cfg(not(feature = "ristretto255"))]
impl CipherSuite for DefaultCipherSuite { impl CipherSuite for DefaultCipherSuite {
type OprfCs = p256::NistP256; type OprfCs = p256::NistP256;
type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
type Ksf = opaque_ke::ksf::Identity; type Ksf = opaque_vx::ksf::Identity;
} }
struct Locker { struct Locker {
contents: Vec<u8>, contents: Vec<u8>,
password_file: GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>, password_file: Vec<u8>,
} }
// Given a key and plaintext, produce an AEAD ciphertext along with a nonce // Given a key and plaintext, produce an AEAD ciphertext along with a nonce
fn encrypt(key: &[u8], plaintext: &[u8]) -> Vec<u8> { fn encrypt(key: &[u8], plaintext: &[u8]) -> Vec<u8> {
let cipher = ChaCha20Poly1305::new(Key::from_slice(&key[..32])); let cipher = ChaCha20Poly1305::new(&Key::try_from(&key[..32]).unwrap());
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let mut nonce_bytes = [0u8; 12]; let mut nonce_bytes = [0u8; 12];
rng.fill_bytes(&mut nonce_bytes); rng.fill_bytes(&mut nonce_bytes);
let nonce = Nonce::from_slice(&nonce_bytes); let nonce = Nonce::try_from(&nonce_bytes[..]).unwrap();
let ciphertext = cipher.encrypt(nonce, plaintext.as_ref()).unwrap(); let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref()).unwrap();
[nonce_bytes.to_vec(), ciphertext].concat() [nonce_bytes.to_vec(), ciphertext].concat()
} }
// Decrypt using a key and a ciphertext (nonce included) to recover the original // Decrypt using a key and a ciphertext (nonce included) to recover the original
// plaintext // plaintext
fn decrypt(key: &[u8], ciphertext: &[u8]) -> Vec<u8> { fn decrypt(key: &[u8], ciphertext: &[u8]) -> Vec<u8> {
let cipher = ChaCha20Poly1305::new(Key::from_slice(&key[..32])); let cipher = ChaCha20Poly1305::new(&Key::try_from(&key[..32]).unwrap());
cipher cipher
.decrypt( .decrypt(
Nonce::from_slice(&ciphertext[..12]), &Nonce::try_from(&ciphertext[..12]).unwrap(),
ciphertext[12..].as_ref(), ciphertext[12..].as_ref(),
) )
.unwrap() .unwrap()
@@ -101,7 +101,7 @@ fn register_locker(
password: String, password: String,
secret_message: String, secret_message: String,
) -> Locker { ) -> Locker {
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()) ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
.unwrap(); .unwrap();
@@ -143,7 +143,7 @@ fn register_locker(
Locker { Locker {
contents: ciphertext, contents: ciphertext,
password_file: password_file.serialize(), password_file: password_file.serialize().to_vec(),
} }
} }
@@ -154,7 +154,7 @@ fn open_locker(
password: String, password: String,
locker: &Locker, locker: &Locker,
) -> Result<String, String> { ) -> Result<String, String> {
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let client_login_start_result = let client_login_start_result =
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap(); ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
let credential_request_bytes = client_login_start_result.message.serialize(); let credential_request_bytes = client_login_start_result.message.serialize();
@@ -163,7 +163,7 @@ fn open_locker(
let password_file = let password_file =
ServerRegistration::<DefaultCipherSuite>::deserialize(&locker.password_file).unwrap(); ServerRegistration::<DefaultCipherSuite>::deserialize(&locker.password_file).unwrap();
let mut server_rng = OsRng; let mut server_rng = UnwrapErr(SysRng);
let server_login_start_result = ServerLogin::start( let server_login_start_result = ServerLogin::start(
&mut server_rng, &mut server_rng,
server_setup, server_setup,
@@ -217,7 +217,7 @@ fn open_locker(
} }
fn main() { fn main() {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng); let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
let mut rl = Editor::<(), _>::new().unwrap(); let mut rl = Editor::<(), _>::new().unwrap();
+18 -18
View File
@@ -22,22 +22,22 @@
//! over "the wire" to the server. These bytes are serialized and explicitly //! over "the wire" to the server. These bytes are serialized and explicitly
//! annotated in the below functions. //! annotated in the below functions.
use std::collections::HashMap; use opaque_vx::argon2::Argon2;
use std::process::exit; use opaque_vx::ciphersuite::CipherSuite;
use opaque_vx::hybrid_array::Array;
use opaque_ke::argon2::Argon2; use opaque_vx::rand::rngs::SysRng;
use opaque_ke::ciphersuite::CipherSuite; use opaque_vx::{
use opaque_ke::generic_array::GenericArray;
use opaque_ke::rand::rngs::OsRng;
use opaque_ke::{
ClientLogin, ClientLoginFinishParameters, ClientRegistration, ClientLogin, ClientLoginFinishParameters, ClientRegistration,
ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest, ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest,
CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin, CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin,
ServerLoginParameters, ServerRegistration, ServerRegistrationLen, ServerSetup, ServerLoginParameters, ServerRegistration, ServerRegistrationLen, ServerSetup,
}; };
use rand_core::UnwrapErr;
use rustyline::Editor; use rustyline::Editor;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::history::DefaultHistory; use rustyline::history::DefaultHistory;
use std::collections::HashMap;
use std::process::exit;
// The ciphersuite trait allows to specify the underlying primitives that will // The ciphersuite trait allows to specify the underlying primitives that will
// be used in the OPAQUE protocol // be used in the OPAQUE protocol
@@ -46,8 +46,8 @@ struct DefaultCipherSuite;
#[cfg(feature = "ristretto255")] #[cfg(feature = "ristretto255")]
impl CipherSuite for DefaultCipherSuite { impl CipherSuite for DefaultCipherSuite {
type OprfCs = opaque_ke::Ristretto255; type OprfCs = opaque_vx::Ristretto255;
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
type Ksf = Argon2<'static>; type Ksf = Argon2<'static>;
} }
@@ -55,7 +55,7 @@ impl CipherSuite for DefaultCipherSuite {
#[cfg(not(feature = "ristretto255"))] #[cfg(not(feature = "ristretto255"))]
impl CipherSuite for DefaultCipherSuite { impl CipherSuite for DefaultCipherSuite {
type OprfCs = p256::NistP256; type OprfCs = p256::NistP256;
type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
type Ksf = Argon2<'static>; type Ksf = Argon2<'static>;
} }
@@ -65,8 +65,8 @@ fn account_registration(
server_setup: &ServerSetup<DefaultCipherSuite>, server_setup: &ServerSetup<DefaultCipherSuite>,
username: String, username: String,
password: String, password: String,
) -> GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>> { ) -> Array<u8, ServerRegistrationLen<DefaultCipherSuite>> {
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()) ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
.unwrap(); .unwrap();
@@ -100,7 +100,7 @@ fn account_registration(
let password_file = ServerRegistration::finish( let password_file = ServerRegistration::finish(
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(), RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
); );
password_file.serialize() password_file.serialize().into_ha0_4()
} }
// Password-based login between a client and server // Password-based login between a client and server
@@ -110,7 +110,7 @@ fn account_login(
password: String, password: String,
password_file_bytes: &[u8], password_file_bytes: &[u8],
) -> bool { ) -> bool {
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let client_login_start_result = let client_login_start_result =
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap(); ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
let credential_request_bytes = client_login_start_result.message.serialize(); let credential_request_bytes = client_login_start_result.message.serialize();
@@ -119,7 +119,7 @@ fn account_login(
let password_file = let password_file =
ServerRegistration::<DefaultCipherSuite>::deserialize(password_file_bytes).unwrap(); ServerRegistration::<DefaultCipherSuite>::deserialize(password_file_bytes).unwrap();
let mut server_rng = OsRng; let mut server_rng = UnwrapErr(SysRng);
let server_login_start_result = ServerLogin::start( let server_login_start_result = ServerLogin::start(
&mut server_rng, &mut server_rng,
server_setup, server_setup,
@@ -161,12 +161,12 @@ fn account_login(
} }
fn main() { fn main() {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng); let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
let mut rl = Editor::<(), _>::new().unwrap(); let mut rl = Editor::<(), _>::new().unwrap();
let mut registered_users = let mut registered_users =
HashMap::<String, GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new(); HashMap::<String, Array<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new();
loop { loop {
println!( println!(
"\nCurrently registered usernames: {:?}\n", "\nCurrently registered usernames: {:?}\n",
+30
View File
@@ -0,0 +1,30 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"dependencyDashboard": true,
"osvVulnerabilityAlerts": true,
"rangeStrategy": "auto",
"packageRules": [
{
"matchManagers": [
"cargo"
],
"groupName": "rust deps"
},
{
"matchManagers": [
"cargo"
],
"matchUpdateTypes": [
"major"
],
"automerge": false
}
],
"lockFileMaintenance": {
"enabled": true
},
"configMigration": true
}
-7
View File
@@ -1,8 +1 @@
format_code_in_doc_comments = true
format_strings = true
group_imports = "StdExternalCrate"
imports_granularity = "Module"
license_template_path = ".cargo/license.rs"
newline_style = "Unix" newline_style = "Unix"
unstable_features = true
wrap_comments = true
+10 -8
View File
@@ -11,7 +11,7 @@
use core::ops::Add; use core::ops::Add;
use digest::core_api::{BlockSizeUser, CoreProxy}; use digest::block_api::{CoreProxy, EagerHash, SmallBlockSizeUser};
use generic_array::ArrayLength; use generic_array::ArrayLength;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256}; use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
@@ -30,16 +30,18 @@ use crate::opaque::MaskedResponseLen;
/// * `Ksf`: A key stretching function, typically used for password hashing /// * `Ksf`: A key stretching function, typically used for password hashing
pub trait CipherSuite pub trait CipherSuite
where where
OprfHash<Self>: Hash, OprfHash<Self>: Hash + EagerHash,
<OprfHash<Self> as CoreProxy>::Core: ProxyHash, <OprfHash<Self> as CoreProxy>::Core: ProxyHash,
<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
// Envelope: Nonce + Hash // Envelope: Nonce + Hash
// MaskedResponse: (Nonce + Hash) + KePk // MaskedResponse: (Nonce + Hash) + KePk
OutputSize<OprfHash<Self>>: Add<NonceLen>, OutputSize<OprfHash<Self>>: Add<NonceLen> + ArrayLength,
Sum<OutputSize<OprfHash<Self>>, NonceLen>: Sum<OutputSize<OprfHash<Self>>, NonceLen>: ArrayLength + Add<<KeGroup<Self> as Group>::PkLen>,
ArrayLength<u8> + Add<<KeGroup<Self> as Group>::PkLen>, MaskedResponseLen<Self>: ArrayLength,
MaskedResponseLen<Self>: ArrayLength<u8>, // hybrid-array interop bounds
<OprfGroup<Self> as voprf::Group>::ScalarLen: ArrayLength,
<OprfGroup<Self> as voprf::Group>::ElemLen: ArrayLength,
{ {
/// A VOPRF ciphersuite, see [`voprf::CipherSuite`]. /// A VOPRF ciphersuite, see [`voprf::CipherSuite`].
type OprfCs: voprf::CipherSuite; type OprfCs: voprf::CipherSuite;
+24 -22
View File
@@ -11,11 +11,10 @@ use core::convert::TryFrom;
use derive_where::derive_where; use derive_where::derive_where;
use digest::Output; use digest::Output;
use generic_array::GenericArray; use generic_array::GenericArray;
use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, U32}; use generic_array::typenum::{Sum, U32};
use hkdf::Hkdf; use hkdf::SimpleHkdf as Hkdf;
use hmac::{Hmac, Mac}; use hmac::{KeyInit, Mac, SimpleHmac};
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use zeroize::Zeroize; use zeroize::Zeroize;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfHash}; use crate::ciphersuite::{CipherSuite, KeGroup, OprfHash};
@@ -108,9 +107,9 @@ pub(crate) type EnvelopeLen<CS: CipherSuite> = Sum<OutputSize<OprfHash<CS>>, Non
impl<CS: CipherSuite> Envelope<CS> { impl<CS: CipherSuite> Envelope<CS> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub(crate) fn seal<R: RngCore + CryptoRng>( pub(crate) fn seal<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>, randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
server_s_pk: &PublicKey<KeGroup<CS>>, server_s_pk: &PublicKey<KeGroup<CS>>,
ids: Identifiers, ids: Identifiers,
) -> Result<SealResult<CS>, ProtocolError> { ) -> Result<SealResult<CS>, ProtocolError> {
@@ -119,7 +118,7 @@ impl<CS: CipherSuite> Envelope<CS> {
let (mode, client_s_pk) = ( let (mode, client_s_pk) = (
InnerEnvelopeMode::Internal, InnerEnvelopeMode::Internal,
build_inner_envelope_internal::<CS>(randomized_pwd_hasher.clone(), nonce)?, build_inner_envelope_internal::<CS>(randomized_pwd_hasher, nonce)?,
); );
let server_s_pk_bytes = server_s_pk.serialize(); let server_s_pk_bytes = server_s_pk.serialize();
@@ -148,7 +147,7 @@ impl<CS: CipherSuite> Envelope<CS> {
/// the aad field. Note that a new nonce is sampled for each call to seal. /// 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<OprfHash<CS>>, 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,
@@ -163,7 +162,7 @@ impl<CS: CipherSuite> Envelope<CS> {
.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 = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key) let mut hmac = SimpleHmac::<OprfHash<CS>>::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);
@@ -184,7 +183,7 @@ impl<CS: CipherSuite> Envelope<CS> {
pub(crate) fn open<'a>( pub(crate) fn open<'a>(
&self, &self,
randomized_pwd_hasher: Hkdf<OprfHash<CS>>, randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
server_s_pk: PublicKey<KeGroup<CS>>, server_s_pk: PublicKey<KeGroup<CS>>,
optional_ids: Identifiers<'a>, optional_ids: Identifiers<'a>,
) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> { ) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> {
@@ -193,7 +192,7 @@ impl<CS: CipherSuite> Envelope<CS> {
return Err(InternalError::IncompatibleEnvelopeModeError.into()); return Err(InternalError::IncompatibleEnvelopeModeError.into());
} }
InnerEnvelopeMode::Internal => { InnerEnvelopeMode::Internal => {
recover_keys_internal::<CS>(randomized_pwd_hasher.clone(), self.nonce)? recover_keys_internal::<CS>(randomized_pwd_hasher, self.nonce)?
} }
}; };
@@ -222,20 +221,20 @@ impl<CS: CipherSuite> Envelope<CS> {
/// if the key and aad used to construct the envelope are the same. /// 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<OprfHash<CS>>, randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
aad: impl Iterator<Item = &'a [u8]>, aad: impl Iterator<Item = &'a [u8]>,
) -> Result<OpenedInnerEnvelope<CS>, InternalError> { ) -> Result<OpenedInnerEnvelope<CS>, InternalError> {
let mut hmac_key = Output::<OprfHash<CS>>::default(); let mut hmac_key = Output::<OprfHash<CS>>::default();
let mut export_key = Output::<OprfHash<CS>>::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_multi_info(&[&self.nonce, &STR_AUTH_KEY], &mut hmac_key)
.map_err(|_| InternalError::HkdfError)?; .map_err(|_| InternalError::HkdfError)?;
randomized_pwd_hasher randomized_pwd_hasher
.expand(&self.nonce.concat(STR_EXPORT_KEY.into()), &mut export_key) .expand_multi_info(&[&self.nonce, &STR_EXPORT_KEY], &mut export_key)
.map_err(|_| InternalError::HkdfError)?; .map_err(|_| InternalError::HkdfError)?;
let mut hmac = Hmac::<OprfHash<CS>>::new_from_slice(&hmac_key) let mut hmac = SimpleHmac::<OprfHash<CS>>::new_from_slice(&hmac_key)
.map_err(|_| InternalError::HmacError)?; .map_err(|_| InternalError::HmacError)?;
hmac.update(&self.nonce); hmac.update(&self.nonce);
hmac.update_iter(aad); hmac.update_iter(aad);
@@ -250,7 +249,7 @@ impl<CS: CipherSuite> Envelope<CS> {
Self { Self {
mode: InnerEnvelopeMode::Zero, mode: InnerEnvelopeMode::Zero,
nonce: GenericArray::default(), nonce: GenericArray::default(),
hmac: GenericArray::default(), hmac: GenericArray::default().into_ha0_4(),
} }
} }
@@ -262,14 +261,17 @@ impl<CS: CipherSuite> Envelope<CS> {
} }
pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>> { pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>> {
self.nonce.concat_ext(&self.hmac) self.nonce
.concat_ext(&GenericArray::from_ha0_4(self.hmac.clone()))
} }
pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> { pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
mode: InnerEnvelopeMode::Internal, mode: InnerEnvelopeMode::Internal,
nonce: bytes.take_array("nonce")?, nonce: bytes.take_array("nonce")?,
hmac: bytes.take_array("hmac")?, hmac: bytes
.take_array::<OutputSize<OprfHash<CS>>>("hmac")?
.into_ha0_4(),
}) })
} }
} }
@@ -277,12 +279,12 @@ impl<CS: CipherSuite> Envelope<CS> {
// Helper functions // Helper functions
fn build_inner_envelope_internal<CS: CipherSuite>( fn build_inner_envelope_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<OprfHash<CS>>, randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>, nonce: GenericArray<u8, NonceLen>,
) -> Result<PublicKey<KeGroup<CS>>, ProtocolError> { ) -> Result<PublicKey<KeGroup<CS>>, ProtocolError> {
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default(); let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
randomized_pwd_hasher randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed) .expand_multi_info(&[&nonce, &STR_PRIVATE_KEY], &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?; .map_err(|_| InternalError::HkdfError)?;
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?); let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
@@ -290,12 +292,12 @@ fn build_inner_envelope_internal<CS: CipherSuite>(
} }
fn recover_keys_internal<CS: CipherSuite>( fn recover_keys_internal<CS: CipherSuite>(
randomized_pwd_hasher: Hkdf<OprfHash<CS>>, randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
nonce: GenericArray<u8, NonceLen>, nonce: GenericArray<u8, NonceLen>,
) -> Result<KeyPair<KeGroup<CS>>, ProtocolError> { ) -> Result<KeyPair<KeGroup<CS>>, ProtocolError> {
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default(); let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
randomized_pwd_hasher randomized_pwd_hasher
.expand(&nonce.concat(STR_PRIVATE_KEY.into()), &mut keypair_seed) .expand_multi_info(&[&nonce, &STR_PRIVATE_KEY], &mut keypair_seed)
.map_err(|_| InternalError::HkdfError)?; .map_err(|_| InternalError::HkdfError)?;
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?); let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
let client_s_pk = client_s_sk.public_key(); let client_s_pk = client_s_sk.public_key();
+3 -2
View File
@@ -141,8 +141,8 @@ impl<T> From<InternalError> for ProtocolError<T> {
// See https://github.com/rust-lang/rust/issues/64715 and remove this when merged, // See https://github.com/rust-lang/rust/issues/64715 and remove this when merged,
// and https://github.com/dtolnay/thiserror/issues/62 for why this comes up in our // and https://github.com/dtolnay/thiserror/issues/62 for why this comes up in our
// doc tests. // doc tests.
impl<T> From<::core::convert::Infallible> for ProtocolError<T> { impl<T> From<Infallible> for ProtocolError<T> {
fn from(_: ::core::convert::Infallible) -> Self { fn from(_: Infallible) -> Self {
unreachable!() unreachable!()
} }
} }
@@ -164,6 +164,7 @@ impl ProtocolError {
actual_len, actual_len,
}, },
Self::ReflectedValueError => ProtocolError::ReflectedValueError, Self::ReflectedValueError => ProtocolError::ReflectedValueError,
Self::Custom(infallible) => match infallible {},
} }
} }
} }
+27 -15
View File
@@ -8,36 +8,45 @@
//! A convenience trait for digest bounds used throughout the library //! A convenience trait for digest bounds used throughout the library
use digest::block_api::{
BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, SmallBlockSizeUser,
};
use digest::block_buffer::Eager; use digest::block_buffer::Eager;
use digest::core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore}; use digest::{Digest, FixedOutputReset, HashMarker, OutputSizeUser};
use digest::{FixedOutputReset, HashMarker, OutputSizeUser};
use generic_array::typenum::{IsLess, Le, NonZero, U256}; use generic_array::typenum::{IsLess, Le, NonZero, U256};
pub(crate) type OutputSize<H> = <<H as CoreProxy>::Core as OutputSizeUser>::OutputSize; pub(crate) type OutputSize<H> = <<H as CoreProxy>::Core as OutputSizeUser>::OutputSize;
/// Trait to simplify requirements for [`Hash`]. /// Trait to simplify requirements for [`Hash`].
pub trait ProxyHash: pub trait ProxyHash:
HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + OutputSizeUser + Default + Clone
where where
<Self as BlockSizeUser>::BlockSize: IsLess<U256>, <Self as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<Self as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
{ {
} }
impl<T: HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone> impl<
ProxyHash for T T: HashMarker
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ OutputSizeUser
+ Default
+ Clone,
> ProxyHash for T
where where
<Self as BlockSizeUser>::BlockSize: IsLess<U256>, <T as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<T as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
{ {
} }
/// Trait inheriting the requirements from [`digest::Digest`] for compatibility /// Trait inheriting the requirements from [`Digest`] for compatibility
/// with HKDF and HMAC Associated types could be simplified when they are made /// with HKDF and HMAC Associated types could be simplified when they are made
/// as defaults: <https://github.com/rust-lang/rust/issues/29661> /// as defaults: <https://github.com/rust-lang/rust/issues/29661>
pub trait Hash: pub trait Hash:
Default Default
+ HashMarker + HashMarker
+ Digest
+ OutputSizeUser<OutputSize = OutputSize<Self>> + OutputSizeUser<OutputSize = OutputSize<Self>>
+ BlockSizeUser + BlockSizeUser
+ FixedOutputReset + FixedOutputReset
@@ -45,14 +54,16 @@ pub trait Hash:
+ Clone + Clone
where where
<Self as CoreProxy>::Core: ProxyHash, <Self as CoreProxy>::Core: ProxyHash,
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<Self>: generic_array::ArrayLength,
{ {
} }
impl< impl<
T: Default T: Default
+ HashMarker + HashMarker
+ Digest
+ OutputSizeUser<OutputSize = OutputSize<Self>> + OutputSizeUser<OutputSize = OutputSize<Self>>
+ BlockSizeUser + BlockSizeUser
+ FixedOutputReset + FixedOutputReset
@@ -60,8 +71,9 @@ impl<
+ Clone, + Clone,
> Hash for T > Hash for T
where where
<Self as CoreProxy>::Core: ProxyHash, <T as CoreProxy>::Core: ProxyHash,
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<T>: generic_array::ArrayLength,
{ {
} }
+2 -2
View File
@@ -14,7 +14,7 @@ use curve25519_dalek::scalar;
use curve25519_dalek::traits::IsIdentity; use curve25519_dalek::traits::IsIdentity;
use generic_array::GenericArray; use generic_array::GenericArray;
use generic_array::typenum::U32; use generic_array::typenum::U32;
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
use zeroize::ZeroizeOnDrop; use zeroize::ZeroizeOnDrop;
@@ -43,7 +43,7 @@ impl Group for Curve25519 {
.and_then(|bytes| NonIdentity::from_bytes(bytes.into())) .and_then(|bytes| NonIdentity::from_bytes(bytes.into()))
} }
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk { fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
// Sample 32 random bytes and then clamp, as described in https://cr.yp.to/ecdh.html // Sample 32 random bytes and then clamp, as described in https://cr.yp.to/ecdh.html
let mut scalar_bytes = [0u8; 32]; let mut scalar_bytes = [0u8; 32];
rng.fill_bytes(&mut scalar_bytes); rng.fill_bytes(&mut scalar_bytes);
+16 -15
View File
@@ -18,9 +18,8 @@ pub use ed25519_dalek;
use ed25519_dalek::hazmat::ExpandedSecretKey; use ed25519_dalek::hazmat::ExpandedSecretKey;
use ed25519_dalek::{SecretKey, Sha512}; use ed25519_dalek::{SecretKey, Sha512};
use generic_array::GenericArray; use generic_array::GenericArray;
use generic_array::sequence::Concat;
use generic_array::typenum::{U32, U64}; use generic_array::typenum::{U32, U64};
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
use super::Group; use super::Group;
@@ -30,7 +29,7 @@ use crate::key_exchange::sigma_i::hash_eddsa::implementation::HashEddsaImpl;
use crate::key_exchange::sigma_i::pure_eddsa::implementation::PureEddsaImpl; use crate::key_exchange::sigma_i::pure_eddsa::implementation::PureEddsaImpl;
pub use crate::key_exchange::sigma_i::shared::PreHash; pub use crate::key_exchange::sigma_i::shared::PreHash;
use crate::key_exchange::sigma_i::{CachedMessage, Message, MessageBuilder}; use crate::key_exchange::sigma_i::{CachedMessage, Message, MessageBuilder};
use crate::serialization::{SliceExt, UpdateExt}; use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// Implementation for Ed25519. /// Implementation for Ed25519.
pub struct Ed25519; pub struct Ed25519;
@@ -46,12 +45,12 @@ impl Group for Ed25519 {
} }
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> { fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
let bytes = bytes.take_array("public key")?; let bytes = bytes.take_array::<U32>("public key")?;
VerifyingKey::from_bytes(bytes.into()) VerifyingKey::from_bytes(bytes.into())
} }
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk { fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
let mut sk = <[u8; 32]>::default(); let mut sk = <[u8; 32]>::default();
rng.fill_bytes(&mut sk); rng.fill_bytes(&mut sk);
@@ -72,7 +71,7 @@ impl Group for Ed25519 {
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> { fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
Ok(SigningKey::from_bytes( Ok(SigningKey::from_bytes(
bytes.take_array("secret key")?.into(), bytes.take_array::<U32>("secret key")?.into(),
)) ))
} }
} }
@@ -399,7 +398,7 @@ pub struct Signature {
} }
impl Signature { impl Signature {
/// Expects the `R` and `s` components of a Ed25519 signature with no added /// Expects the `R` and `s` components of an Ed25519 signature with no added
/// framing. /// framing.
pub fn from_slice(mut bytes: &[u8]) -> Result<Self, ProtocolError> { pub fn from_slice(mut bytes: &[u8]) -> Result<Self, ProtocolError> {
Self::deserialize_take(&mut bytes) Self::deserialize_take(&mut bytes)
@@ -407,9 +406,9 @@ impl Signature {
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
#[allow(non_snake_case)] #[allow(non_snake_case)]
let R = CompressedEdwardsY(bytes.take_array("signature R")?.into()); let R = CompressedEdwardsY(bytes.take_array::<U32>("signature R")?.into());
let s = Scalar::from_canonical_bytes(bytes.take_array("signature s")?.into()) let s = Scalar::from_canonical_bytes(bytes.take_array::<U32>("signature s")?.into())
.into_option() .into_option()
.ok_or(ProtocolError::SerializationError)?; .ok_or(ProtocolError::SerializationError)?;
@@ -417,7 +416,8 @@ impl Signature {
} }
fn serialize(&self) -> GenericArray<u8, U64> { fn serialize(&self) -> GenericArray<u8, U64> {
GenericArray::from(self.R.0).concat(GenericArray::from(self.s.to_bytes())) GenericArray::<u8, U32>::from(self.R.0)
.cat(GenericArray::<u8, U32>::from(self.s.to_bytes()))
} }
} }
@@ -433,17 +433,18 @@ mod test {
use std::iter; use std::iter;
use ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey}; use ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey};
use rand::rngs::OsRng; use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use super::*; use super::*;
#[test] #[test]
fn pure_eddsa() { fn pure_eddsa() {
let mut message = [0; 1024]; let mut message = [0; 1024];
OsRng.fill_bytes(&mut message); UnwrapErr(SysRng).fill_bytes(&mut message);
let mut sk = SecretKey::default(); let mut sk = SecretKey::default();
OsRng.fill_bytes(&mut sk); UnwrapErr(SysRng).fill_bytes(&mut sk);
let signing_key = SigningKey::from_bytes(&sk); let signing_key = SigningKey::from_bytes(&sk);
let signature = signing_key.sign(&message); let signature = signing_key.sign(&message);
@@ -472,12 +473,12 @@ mod test {
#[test] #[test]
fn hash_eddsa() { fn hash_eddsa() {
let mut message = [0; 1024]; let mut message = [0; 1024];
OsRng.fill_bytes(&mut message); UnwrapErr(SysRng).fill_bytes(&mut message);
let message = Sha512::new_with_prefix(message); let message = Sha512::new_with_prefix(message);
let pre_hash = message.clone().finalize(); let pre_hash = message.clone().finalize();
let mut sk = SecretKey::default(); let mut sk = SecretKey::default();
OsRng.fill_bytes(&mut sk); UnwrapErr(SysRng).fill_bytes(&mut sk);
let signing_key = SigningKey::from_bytes(&sk); let signing_key = SigningKey::from_bytes(&sk);
let signature = signing_key.sign_prehashed(message.clone(), None).unwrap(); let signature = signing_key.sign_prehashed(message.clone(), None).unwrap();
+50 -67
View File
@@ -8,17 +8,18 @@
//! Implementation for EC curves via [`elliptic_curve`] traits. //! Implementation for EC curves via [`elliptic_curve`] traits.
use core::fmt::{self, Debug, Formatter}; use core::ops::Mul;
use digest::OutputSizeUser;
use derive_where::derive_where; use digest::block_api::BlockSizeUser;
use elliptic_curve::group::GroupEncoding; use elliptic_curve::group::GroupEncoding;
use elliptic_curve::ops::MulByGenerator; use elliptic_curve::point::NonIdentity;
use elliptic_curve::sec1::{ModulusSize, ToEncodedPoint}; use elliptic_curve::sec1::{ModulusSize, ToSec1Point};
use elliptic_curve::{ use elliptic_curve::{
CurveArithmetic, FieldBytesSize, NonZeroScalar, ProjectivePoint, Scalar, SecretKey, point, CurveArithmetic, FieldBytesSize, Generate, NonZeroScalar, ProjectivePoint, Scalar, SecretKey,
}; };
use generic_array::GenericArray; use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U256};
use rand::{CryptoRng, RngCore}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, Rng};
use voprf::Mode; use voprf::Mode;
use super::{Group, STR_OPAQUE_DERIVE_AUTH_KEY_PAIR}; use super::{Group, STR_OPAQUE_DERIVE_AUTH_KEY_PAIR};
@@ -29,15 +30,27 @@ use crate::serialization::SliceExt;
impl<G> Group for G impl<G> Group for G
where where
Self: CurveArithmetic + voprf::CipherSuite<Group = Self> + voprf::Group<Scalar = Scalar<Self>>, Self: CurveArithmetic + voprf::CipherSuite<Group = Self> + voprf::Group<Scalar = Scalar<Self>>,
FieldBytesSize<Self>: ModulusSize, FieldBytesSize<Self>: ModulusSize + ArrayLength,
<FieldBytesSize<Self> as ModulusSize>::CompressedPointSize: ArrayLength,
ProjectivePoint<Self>: GroupEncoding< ProjectivePoint<Self>: GroupEncoding<
Repr = GenericArray<u8, <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize>, Repr = hybrid_array::Array<
> + ToEncodedPoint<Self>, u8,
<FieldBytesSize<Self> as ModulusSize>::CompressedPointSize,
>,
> + ToSec1Point<Self>,
// Bounds required by voprf::CipherSuite
<Self as voprf::Group>::SecurityLevel: Mul<U2>,
<<Self as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize: ArrayLength
+ IsLess<U256>
+ IsLessOrEqual<
<<Self as voprf::CipherSuite>::Hash as BlockSizeUser>::BlockSize,
Output = True,
> + IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{ {
// We don't use `elliptic_curve::PublicKey` because it stores its internals in a // We don't use `elliptic_curve::PublicKey` because it stores its internals in a
// format ideal for serialization and not computation. This is inconsistent with // format ideal for serialization and not computation. This is inconsistent with
// our other implementations. // our other implementations.
type Pk = NonIdentity<Self>; type Pk = NonIdentity<ProjectivePoint<Self>>;
type PkLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize; type PkLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
@@ -46,18 +59,19 @@ where
type SkLen = FieldBytesSize<Self>; type SkLen = FieldBytesSize<Self>;
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> { fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen> {
GenericArray::clone_from_slice(pk.0.to_encoded_point(true).as_bytes()) GenericArray::from_slice(pk.to_sec1_point(true).as_bytes()).clone()
} }
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> { fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
point::NonIdentity::<ProjectivePoint<Self>>::from_bytes(&bytes.take_array("public key")?) NonIdentity::<ProjectivePoint<Self>>::from_bytes(
.into_option() &bytes.take_array("public key")?.into_ha0_4(),
.map(NonIdentity) )
.ok_or(ProtocolError::SerializationError) .into_option()
.ok_or(ProtocolError::SerializationError)
} }
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk { fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
SecretKey::<Self>::random(rng) SecretKey::<Self>::generate_from_rng(rng)
} }
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> { fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError> {
@@ -70,21 +84,15 @@ where
} }
fn public_key(sk: &Self::Sk) -> Self::Pk { fn public_key(sk: &Self::Sk) -> Self::Pk {
// Non-panicking version in https://github.com/RustCrypto/traits/pull/1833. NonIdentity::<ProjectivePoint<Self>>::mul_by_generator(&sk.to_nonzero_scalar())
NonIdentity(
point::NonIdentity::new(ProjectivePoint::<Self>::mul_by_generator(
&sk.to_nonzero_scalar(),
))
.expect("multiplying with a non-zero scalar can never yield the identity element"),
)
} }
fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> { fn serialize_sk(sk: &Self::Sk) -> GenericArray<u8, Self::SkLen> {
sk.to_bytes() GenericArray::from(sk.to_bytes())
} }
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> { fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
SecretKey::<Self>::from_bytes(&bytes.take_array("secret key")?) SecretKey::<Self>::from_bytes(&bytes.take_array("secret key")?.into_ha0_4())
.map_err(|_| ProtocolError::SerializationError) .map_err(|_| ProtocolError::SerializationError)
} }
} }
@@ -92,51 +100,26 @@ where
impl<G> DiffieHellman<G> for SecretKey<G> impl<G> DiffieHellman<G> for SecretKey<G>
where where
G: CurveArithmetic + voprf::CipherSuite<Group = G> + voprf::Group<Scalar = Scalar<G>>, G: CurveArithmetic + voprf::CipherSuite<Group = G> + voprf::Group<Scalar = Scalar<G>>,
FieldBytesSize<G>: ModulusSize, FieldBytesSize<G>: ModulusSize + ArrayLength,
<FieldBytesSize<G> as ModulusSize>::CompressedPointSize: ArrayLength,
ProjectivePoint<G>: GroupEncoding< ProjectivePoint<G>: GroupEncoding<
Repr = GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>, Repr = hybrid_array::Array<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>,
> + ToEncodedPoint<G>, > + ToSec1Point<G>,
<G as voprf::Group>::SecurityLevel: Mul<U2>,
<<G as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize: ArrayLength
+ IsLess<U256>
+ IsLessOrEqual<<<G as voprf::CipherSuite>::Hash as BlockSizeUser>::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<G as voprf::Group>::SecurityLevel, U2>, Output = True>,
{ {
fn diffie_hellman( fn diffie_hellman(
&self, &self,
pk: &NonIdentity<G>, pk: &NonIdentity<ProjectivePoint<G>>,
) -> GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize> { ) -> GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize> {
GenericArray::clone_from_slice( GenericArray::from_slice(
(pk.0 * self.to_nonzero_scalar()) (pk * self.to_nonzero_scalar())
.to_encoded_point(true) .to_sec1_point(true)
.as_bytes(), .as_bytes(),
) )
.clone()
} }
} }
/// Wrapper around [`NonIdentity`](point::NonIdentity) to [`Eq`].
// TODO: remove after https://github.com/RustCrypto/traits/pull/1834.
#[derive_where(Clone, Copy)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
bound(
deserialize = "point::NonIdentity<ProjectivePoint<G>>: serde::Deserialize<'de>",
serialize = "point::NonIdentity<ProjectivePoint<G>>: serde::Serialize"
),
transparent
)
)]
pub struct NonIdentity<G: CurveArithmetic>(pub point::NonIdentity<ProjectivePoint<G>>);
impl<G: CurveArithmetic> Debug for NonIdentity<G> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("NonIdentity")
.field(&self.0.to_point())
.finish()
}
}
impl<G: CurveArithmetic> PartialEq for NonIdentity<G> {
fn eq(&self, other: &Self) -> bool {
self.0.to_point().eq(&other.0.to_point())
}
}
impl<G: CurveArithmetic> Eq for NonIdentity<G> {}
+5 -4
View File
@@ -17,7 +17,8 @@ pub mod elliptic_curve;
pub mod ristretto255; pub mod ristretto255;
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use hybrid_array::ArraySize;
use rand::{CryptoRng, Rng};
use zeroize::ZeroizeOnDrop; use zeroize::ZeroizeOnDrop;
use crate::errors::{InternalError, ProtocolError}; use crate::errors::{InternalError, ProtocolError};
@@ -29,11 +30,11 @@ pub trait Group {
/// Public key /// Public key
type Pk: Clone; type Pk: Clone;
/// Length of the public key /// Length of the public key
type PkLen: ArrayLength<u8>; type PkLen: ArrayLength + ArraySize;
/// Secret key /// Secret key
type Sk: Clone + ZeroizeOnDrop; type Sk: Clone + ZeroizeOnDrop;
/// Length of the secret key /// Length of the secret key
type SkLen: ArrayLength<u8>; type SkLen: ArrayLength + ArraySize;
/// Serializes `self` /// Serializes `self`
fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen>; fn serialize_pk(pk: &Self::Pk) -> GenericArray<u8, Self::PkLen>;
@@ -44,7 +45,7 @@ pub trait Group {
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError>; fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError>;
/// Generate a random secret key /// Generate a random secret key
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk; fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk;
/// Deterministically derive a [`Self::Sk`] from `seed`. /// Deterministically derive a [`Self::Sk`] from `seed`.
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>; fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>;
+24 -13
View File
@@ -13,11 +13,12 @@ use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::IsIdentity; use curve25519_dalek::traits::IsIdentity;
use digest::core_api::BlockSizeUser; use digest::block_api::BlockSizeUser;
use digest::{FixedOutput, HashMarker}; use digest::{FixedOutput, HashMarker};
use generic_array::GenericArray; use generic_array::GenericArray;
use generic_array::typenum::{IsLess, IsLessOrEqual, U32, U256}; use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U32, U256};
use rand::{CryptoRng, RngCore}; use hybrid_array::Array;
use rand::{CryptoRng, Rng, TryCryptoRng, TryRng};
use voprf::Mode; use voprf::Mode;
use zeroize::ZeroizeOnDrop; use zeroize::ZeroizeOnDrop;
@@ -42,15 +43,19 @@ impl Group for Ristretto255 {
} }
fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> { fn deserialize_take_pk(bytes: &mut &[u8]) -> Result<Self::Pk, ProtocolError> {
CompressedRistretto(bytes.take_array("public key")?.into()) CompressedRistretto(bytes.take_array::<U32>("public key")?.into())
.decompress() .decompress()
.ok_or(ProtocolError::SerializationError) .ok_or(ProtocolError::SerializationError)
.and_then(NonIdentity::from_point) .and_then(NonIdentity::from_point)
} }
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk { fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
loop { loop {
let scalar = Scalar::random(rng); let mut bytes = [0u8; 64];
rng.fill_bytes(&mut bytes);
let scalar = Scalar::from_bytes_mod_order_wide(&bytes);
if scalar != Scalar::ZERO { if scalar != Scalar::ZERO {
break NonZeroScalar(scalar); break NonZeroScalar(scalar);
@@ -73,7 +78,7 @@ impl Group for Ristretto255 {
} }
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> { fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
Scalar::from_canonical_bytes(bytes.take_array("secret key")?.into()) Scalar::from_canonical_bytes(bytes.take_array::<U32>("secret key")?.into())
.into_option() .into_option()
.ok_or(ProtocolError::SerializationError) .ok_or(ProtocolError::SerializationError)
.and_then(NonZeroScalar::from_scalar) .and_then(NonZeroScalar::from_scalar)
@@ -149,7 +154,7 @@ where
} }
impl voprf::CipherSuite for Ristretto255 { impl voprf::CipherSuite for Ristretto255 {
const ID: &'static str = voprf::Ristretto255::ID; const ID: &'static [u8] = voprf::Ristretto255::ID;
type Group = <voprf::Ristretto255 as voprf::CipherSuite>::Group; type Group = <voprf::Ristretto255 as voprf::CipherSuite>::Group;
@@ -165,13 +170,17 @@ impl voprf::Group for Ristretto255 {
type ScalarLen = <voprf::Ristretto255 as voprf::Group>::ScalarLen; type ScalarLen = <voprf::Ristretto255 as voprf::Group>::ScalarLen;
type SecurityLevel = <voprf::Ristretto255 as voprf::Group>::SecurityLevel;
fn hash_to_curve<H>( fn hash_to_curve<H>(
input: &[&[u8]], input: &[&[u8]],
dst: &[&[u8]], dst: &[&[u8]],
) -> voprf::Result<Self::Elem, voprf::InternalError> ) -> voprf::Result<Self::Elem, voprf::InternalError>
where where
H: BlockSizeUser + Default + FixedOutput + HashMarker, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256>
+ IsLessOrEqual<H::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{ {
<voprf::Ristretto255 as voprf::Group>::hash_to_curve::<H>(input, dst) <voprf::Ristretto255 as voprf::Group>::hash_to_curve::<H>(input, dst)
} }
@@ -182,7 +191,9 @@ impl voprf::Group for Ristretto255 {
) -> voprf::Result<Self::Scalar, voprf::InternalError> ) -> voprf::Result<Self::Scalar, voprf::InternalError>
where where
H: BlockSizeUser + Default + FixedOutput + HashMarker, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256>
+ IsLessOrEqual<H::BlockSize, Output = True>
+ IsGreaterOrEqual<Prod<<Self as voprf::Group>::SecurityLevel, U2>, Output = True>,
{ {
<voprf::Ristretto255 as voprf::Group>::hash_to_scalar::<H>(input, dst) <voprf::Ristretto255 as voprf::Group>::hash_to_scalar::<H>(input, dst)
} }
@@ -195,7 +206,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::identity_elem() <voprf::Ristretto255 as voprf::Group>::identity_elem()
} }
fn serialize_elem(elem: Self::Elem) -> GenericArray<u8, Self::ElemLen> { fn serialize_elem(elem: Self::Elem) -> Array<u8, Self::ElemLen> {
<voprf::Ristretto255 as voprf::Group>::serialize_elem(elem) <voprf::Ristretto255 as voprf::Group>::serialize_elem(elem)
} }
@@ -203,7 +214,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::deserialize_elem(element_bits) <voprf::Ristretto255 as voprf::Group>::deserialize_elem(element_bits)
} }
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar { fn random_scalar<R: TryRng + TryCryptoRng>(rng: &mut R) -> voprf::Result<Self::Scalar> {
<voprf::Ristretto255 as voprf::Group>::random_scalar(rng) <voprf::Ristretto255 as voprf::Group>::random_scalar(rng)
} }
@@ -215,7 +226,7 @@ impl voprf::Group for Ristretto255 {
<voprf::Ristretto255 as voprf::Group>::is_zero_scalar(scalar) <voprf::Ristretto255 as voprf::Group>::is_zero_scalar(scalar)
} }
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> { fn serialize_scalar(scalar: Self::Scalar) -> Array<u8, Self::ScalarLen> {
<voprf::Ristretto255 as voprf::Group>::serialize_scalar(scalar) <voprf::Ristretto255 as voprf::Group>::serialize_scalar(scalar)
} }
+32 -22
View File
@@ -21,11 +21,12 @@ use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::Output; use digest::Output;
use digest::core_api::{BlockSizeUser, CoreProxy}; use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U2, U256}; use generic_array::typenum::{IsLess, Le, NonZero, Sum, U2, U256};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use hybrid_array::Array;
use rand::{CryptoRng, Rng};
use voprf::{BlindedElement, EvaluationElement}; use voprf::{BlindedElement, EvaluationElement};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -33,7 +34,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::ciphersuite::KeHash; use crate::ciphersuite::KeHash;
use crate::ciphersuite::{CipherSuite, OprfGroup}; use crate::ciphersuite::{CipherSuite, OprfGroup};
use crate::errors::ProtocolError; use crate::errors::ProtocolError;
use crate::hash::{Hash, ProxyHash}; use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::Group; use crate::key_exchange::group::Group;
use crate::key_exchange::shared::{NonceLen, STR_CONTEXT}; use crate::key_exchange::shared::{NonceLen, STR_CONTEXT};
use crate::keypair::{PrivateKey, PublicKey}; use crate::keypair::{PrivateKey, PublicKey};
@@ -44,8 +45,9 @@ use crate::serialization::{SliceExt, i2osp};
pub trait KeyExchange pub trait KeyExchange
where where
<Self::Hash as CoreProxy>::Core: ProxyHash, <Self::Hash as CoreProxy>::Core: ProxyHash,
<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<Self::Hash>: ArrayLength,
{ {
/// The group used for the key exchange. /// The group used for the key exchange.
type Group: Group; type Group: Group;
@@ -71,12 +73,12 @@ where
/// Client generates [`KE1Message`](Self::KE1Message) and /// Client generates [`KE1Message`](Self::KE1Message) and
/// [`KE1State`](Self::KE1State). /// [`KE1State`](Self::KE1State).
fn generate_ke1<R: RngCore + CryptoRng>( fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError>; ) -> Result<GenerateKe1Result<Self>, ProtocolError>;
/// Server generates [`KE2Builder`](Self::KE2Builder). /// Server generates [`KE2Builder`](Self::KE2Builder).
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>( fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -92,7 +94,7 @@ where
) -> Self::KE2BuilderData<'a, CS>; ) -> Self::KE2BuilderData<'a, CS>;
/// Server generates the input without a remote key. /// Server generates the input without a remote key.
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>, builder: &Self::KE2Builder<'_, CS>,
rng: &mut R, rng: &mut R,
server_s_sk: &PrivateKey<Self::Group>, server_s_sk: &PrivateKey<Self::Group>,
@@ -107,7 +109,7 @@ where
/// Client generates [`KE3Message`](Self::KE3Message) and the session key. /// Client generates [`KE3Message`](Self::KE3Message) and the session key.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -137,7 +139,7 @@ where
)] )]
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
pub struct SerializedCredentialRequest<CS: CipherSuite>( pub struct SerializedCredentialRequest<CS: CipherSuite>(
GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>, Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
); );
impl<CS: CipherSuite> SerializedCredentialRequest<CS> { impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
@@ -154,17 +156,20 @@ impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
/// Returns a [`SerializedCredentialRequest`] deserialized from the given /// Returns a [`SerializedCredentialRequest`] deserialized from the given
/// `bytes`. /// `bytes`.
pub fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self(bytes.take_array("blinded element")?)) Ok(Self(bytes.take_array("blinded element")?.into_ha0_4()))
} }
} }
type SerializedCredentialRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Group>::ElemLen; type SerializedCredentialRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Group>::ElemLen;
impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS> { impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS>
where
<OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
{
type Len = SerializedCredentialRequestLen<CS>; type Len = SerializedCredentialRequestLen<CS>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone() GenericArray::from_slice(self.0.as_slice()).clone()
} }
} }
@@ -176,7 +181,7 @@ impl<CS: CipherSuite> Serialize for SerializedCredentialRequest<CS> {
)] )]
#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)] #[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
pub struct SerializedCredentialResponse<CS: CipherSuite> { pub struct SerializedCredentialResponse<CS: CipherSuite> {
evaluation_element: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>, evaluation_element: Array<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>,
masking_nonce: GenericArray<u8, NonceLen>, masking_nonce: GenericArray<u8, NonceLen>,
masked_response: MaskedResponse<CS>, masked_response: MaskedResponse<CS>,
} }
@@ -207,7 +212,7 @@ impl<CS: CipherSuite> SerializedCredentialResponse<CS> {
/// `bytes`. /// `bytes`.
pub fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
evaluation_element: input.take_array("evaluation element")?, evaluation_element: input.take_array("evaluation element")?.into_ha0_4(),
masking_nonce: input.take_array("masking nonce")?, masking_nonce: input.take_array("masking nonce")?,
masked_response: MaskedResponse::deserialize_take(input)?, masked_response: MaskedResponse::deserialize_take(input)?,
}) })
@@ -221,16 +226,21 @@ impl<CS: CipherSuite> Serialize for SerializedCredentialResponse<CS>
where where
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength<u8>, SerializedCredentialResponseLen<CS>: ArrayLength,
{ {
type Len = SerializedCredentialResponseLen<CS>; type Len = SerializedCredentialResponseLen<CS>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.evaluation_element let elem = GenericArray::<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>::from_slice(
.clone() self.evaluation_element.as_slice(),
.concat(self.masking_nonce) )
.concat(self.masked_response.serialize()) .clone();
Concat::concat(
Concat::concat(elem, self.masking_nonce),
self.masked_response.serialize(),
)
} }
} }
@@ -359,7 +369,7 @@ pub trait Deserialize: Sized {
/// Serialization trait for key exchange types. /// Serialization trait for key exchange types.
pub trait Serialize { pub trait Serialize {
/// The length of the serialized types. /// The length of the serialized types.
type Len: ArrayLength<u8>; type Len: ArrayLength;
/// Serialize [`Self`] to a fixed-length byte array. /// Serialize [`Self`] to a fixed-length byte array.
fn serialize(&self) -> GenericArray<u8, Self::Len>; fn serialize(&self) -> GenericArray<u8, Self::Len>;
+45 -34
View File
@@ -9,14 +9,15 @@
use core::ops::Add; use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use digest::{Digest, Mac, Output, OutputSizeUser, Update}; use digest::{Digest, Mac, Output, OutputSizeUser, Update};
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U1, U2, U32, U256, Unsigned}; use generic_array::typenum::{IsLess, Le, NonZero, Sum, U1, U2, U32, U256, Unsigned};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract}; use hkdf::SimpleHkdf as Hkdf;
use hmac::Hmac; use hkdf::SimpleHkdfExtract as HkdfExtract;
use rand::{CryptoRng, RngCore}; use hmac::{KeyInit, SimpleHmac};
use rand::{CryptoRng, Rng};
use super::{ use super::{
Deserialize, GenerateKe1Result, KeyExchange, Serialize, SerializedContext, Deserialize, GenerateKe1Result, KeyExchange, Serialize, SerializedContext,
@@ -106,8 +107,9 @@ pub(super) struct DerivedKeys<H: OutputSizeUser> {
pub(super) struct Ke2BuilderCommon<G: Group, H: Hash> pub(super) struct Ke2BuilderCommon<G: Group, H: Hash>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
G::Sk: DiffieHellman<G>, G::Sk: DiffieHellman<G>,
{ {
pub(super) server_nonce: GenericArray<u8, NonceLen>, pub(super) server_nonce: GenericArray<u8, NonceLen>,
@@ -126,7 +128,7 @@ where
// Helper functions // Helper functions
pub(super) fn generate_ke1< pub(super) fn generate_ke1<
R: RngCore + CryptoRng, R: Rng + CryptoRng,
KE: KeyExchange<KE1State = Ke1State<G>, KE1Message = Ke1Message<G>>, KE: KeyExchange<KE1State = Ke1State<G>, KE1Message = Ke1Message<G>>,
G: Group, G: Group,
>( >(
@@ -150,7 +152,7 @@ pub(super) fn generate_ke1<
} }
// Generate a random nonce up to NonceLen::USIZE bytes. // Generate a random nonce up to NonceLen::USIZE bytes.
pub(super) fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> GenericArray<u8, NonceLen> { pub(super) fn generate_nonce<R: Rng + CryptoRng>(rng: &mut R) -> GenericArray<u8, NonceLen> {
let mut nonce_bytes = GenericArray::default(); let mut nonce_bytes = GenericArray::default();
rng.fill_bytes(&mut nonce_bytes); rng.fill_bytes(&mut nonce_bytes);
nonce_bytes nonce_bytes
@@ -190,11 +192,12 @@ pub(super) fn ke2_builder_common<'a, G, H, CS, R>(
where where
G: Group, G: Group,
H: Hash, H: Hash,
R: RngCore + CryptoRng, R: Rng + CryptoRng,
CS: CipherSuite, CS: CipherSuite,
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
G::Sk: DiffieHellman<G>, G::Sk: DiffieHellman<G>,
CS::KeyExchange: KeyExchange<Group = G, Hash = H>, CS::KeyExchange: KeyExchange<Group = G, Hash = H>,
{ {
@@ -238,8 +241,9 @@ pub(super) fn derive_keys<'a, H: Hash>(
) -> Result<DerivedKeys<H>, ProtocolError> ) -> Result<DerivedKeys<H>, ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
let mut hkdf = HkdfExtract::<H>::new(None); let mut hkdf = HkdfExtract::<H>::new(None);
@@ -280,19 +284,20 @@ pub(super) fn compute_ke2_macs<H: Hash>(
) -> Result<(Output<H>, Output<H>), ProtocolError> ) -> Result<(Output<H>, Output<H>), ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
let mut mac_hasher = let mut mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; SimpleHmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut mac_hasher, transcript_digest); Mac::update(&mut mac_hasher, transcript_digest);
let mac = mac_hasher.finalize().into_bytes(); let mac = mac_hasher.finalize().into_bytes();
transcript_hasher.update(&mac); Update::update(transcript_hasher, &mac);
let finalized_transcript = transcript_hasher.clone().finalize(); let finalized_transcript = transcript_hasher.clone().finalize();
let mut expected_mac_hasher = let mut expected_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; SimpleHmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut expected_mac_hasher, &finalized_transcript); Mac::update(&mut expected_mac_hasher, &finalized_transcript);
let expected_mac = expected_mac_hasher.finalize().into_bytes(); let expected_mac = expected_mac_hasher.finalize().into_bytes();
@@ -311,23 +316,24 @@ pub(super) fn finalize_ke3_transcript<'a, H: Hash>(
) -> Result<(DerivedKeys<H>, Output<H>), ProtocolError> ) -> Result<(DerivedKeys<H>, Output<H>), ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
let transcript_digest = transcript_hasher.clone().finalize(); let transcript_digest = transcript_hasher.clone().finalize();
let derived_keys = derive_keys::<H>(shared_secrets, &transcript_digest)?; let derived_keys = derive_keys::<H>(shared_secrets, &transcript_digest)?;
let mut server_mac_hasher = let mut server_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; SimpleHmac::<H>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut server_mac_hasher, &transcript_digest); Mac::update(&mut server_mac_hasher, &transcript_digest);
server_mac_hasher server_mac_hasher
.verify(server_mac) .verify(server_mac)
.map_err(|_| ProtocolError::InvalidLoginError)?; .map_err(|_| ProtocolError::InvalidLoginError)?;
transcript_hasher.update(server_mac.as_slice()); Update::update(transcript_hasher, server_mac);
let finalized_transcript = transcript_hasher.clone().finalize(); let finalized_transcript = transcript_hasher.clone().finalize();
let mut client_mac_hasher = let mut client_mac_hasher =
Hmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; SimpleHmac::<H>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
Mac::update(&mut client_mac_hasher, &finalized_transcript); Mac::update(&mut client_mac_hasher, &finalized_transcript);
let client_mac = client_mac_hasher.finalize().into_bytes(); let client_mac = client_mac_hasher.finalize().into_bytes();
@@ -342,8 +348,9 @@ fn hkdf_expand_label<H: Hash>(
) -> Result<Output<H>, ProtocolError> ) -> Result<Output<H>, ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
let h = Hkdf::<H>::from_prk(secret).map_err(|_| InternalError::HkdfError)?; let h = Hkdf::<H>::from_prk(secret).map_err(|_| InternalError::HkdfError)?;
hkdf_expand_label_extracted(&h, label, context) hkdf_expand_label_extracted(&h, label, context)
@@ -356,10 +363,11 @@ fn hkdf_expand_label_extracted<H: Hash>(
) -> Result<Output<H>, ProtocolError> ) -> Result<Output<H>, ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
let mut okm = GenericArray::default(); let mut okm = GenericArray::default().into_ha0_4();
let length = i2osp::<U2>(OutputSize::<H>::USIZE)?; let length = i2osp::<U2>(OutputSize::<H>::USIZE)?;
let label_length = i2osp::<U1>(STR_OPAQUE.len() + label.len())?; let label_length = i2osp::<U1>(STR_OPAQUE.len() + label.len())?;
@@ -386,8 +394,9 @@ fn derive_secrets<H: Hash>(
) -> Result<Output<H>, ProtocolError> ) -> Result<Output<H>, ProtocolError>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
hkdf_expand_label_extracted::<H>(hkdf, label, hashed_derivation_transcript) hkdf_expand_label_extracted::<H>(hkdf, label, hashed_derivation_transcript)
} }
@@ -407,12 +416,14 @@ impl<G: Group> Serialize for Ke1State<G>
where where
// Ke1State: KeSk + Nonce // Ke1State: KeSk + Nonce
G::SkLen: Add<NonceLen>, G::SkLen: Add<NonceLen>,
Sum<G::SkLen, NonceLen>: ArrayLength<u8>, Sum<G::SkLen, NonceLen>: ArrayLength,
{ {
type Len = Sum<G::SkLen, NonceLen>; type Len = Sum<G::SkLen, NonceLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_e_sk.serialize().concat(self.client_nonce) let a = self.client_e_sk.serialize();
GenericArray::concat(a, self.client_nonce)
} }
} }
@@ -429,7 +440,7 @@ impl<G: Group> Serialize for Ke1Message<G>
where where
// Ke1Message: Nonce + KePk // Ke1Message: Nonce + KePk
NonceLen: Add<G::PkLen>, NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8>, Sum<NonceLen, G::PkLen>: ArrayLength,
{ {
type Len = Sum<NonceLen, G::PkLen>; type Len = Sum<NonceLen, G::PkLen>;
@@ -476,7 +487,7 @@ impl<G: Group> Ke1MessageIter<G> {
impl<G: Group> Ke1MessageIter<G> impl<G: Group> Ke1MessageIter<G>
where where
NonceLen: Add<G::PkLen>, NonceLen: Add<G::PkLen>,
Ke1MessageIterLen<G>: ArrayLength<u8>, Ke1MessageIterLen<G>: ArrayLength,
{ {
pub(crate) fn serialize(&self) -> GenericArray<u8, Ke1MessageIterLen<G>> { pub(crate) fn serialize(&self) -> GenericArray<u8, Ke1MessageIterLen<G>> {
self.client_nonce.concat(self.client_e_pk.clone()) self.client_nonce.concat(self.client_e_pk.clone())
+40 -85
View File
@@ -11,23 +11,19 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use derive_where::derive_where; use digest::block_api::{BlockSizeUser, EagerHash};
use digest::core_api::BlockSizeUser; use digest::{Digest, FixedOutputReset, HashMarker};
use digest::{FixedOutputReset, HashMarker}; use ecdsa::{EcdsaCurve, SignatureSize};
use ecdsa::{PrimeCurve, SignatureSize, hazmat}; use elliptic_curve::point::NonIdentity;
use elliptic_curve::{ use elliptic_curve::{CurveArithmetic, FieldBytes, ProjectivePoint, SecretKey};
CurveArithmetic, Field, FieldBytes, FieldBytesEncoding, FieldBytesSize, PrimeField, Scalar,
SecretKey,
};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use hybrid_array::ArraySize;
use zeroize::Zeroize; use rand::{CryptoRng, Rng};
use super::{Message, MessageBuilder, SignatureProtocol}; use super::{Message, MessageBuilder, SignatureProtocol};
use crate::ciphersuite::CipherSuite; use crate::ciphersuite::CipherSuite;
use crate::errors::ProtocolError; use crate::errors::ProtocolError;
use crate::key_exchange::group::Group; use crate::key_exchange::group::Group;
use crate::key_exchange::group::elliptic_curve::NonIdentity;
pub use crate::key_exchange::sigma_i::shared::PreHash; pub use crate::key_exchange::sigma_i::shared::PreHash;
use crate::serialization::SliceExt; use crate::serialization::SliceExt;
@@ -39,23 +35,21 @@ pub struct Ecdsa<G, H>(PhantomData<(G, H)>);
impl<G, H> SignatureProtocol for Ecdsa<G, H> impl<G, H> SignatureProtocol for Ecdsa<G, H>
where where
G: CurveArithmetic + Group<Sk = SecretKey<G>, Pk = NonIdentity<G>> + PrimeCurve, G: CurveArithmetic
SignatureSize<G>: ArrayLength<u8>, + Group<Sk = SecretKey<G>, Pk = NonIdentity<ProjectivePoint<G>>>
H: Clone + EcdsaCurve,
+ Default SignatureSize<G>: ArrayLength + ArraySize,
+ BlockSizeUser H: EagerHash + FixedOutputReset + BlockSizeUser + HashMarker + Digest + Clone + Default,
+ FixedOutputReset<OutputSize = FieldBytesSize<G>>
+ HashMarker,
{ {
type Group = G; type Group = G;
type Signature = Signature<G>; type Signature = ecdsa::Signature<G>;
type SignatureLen = SignatureSize<G>; type SignatureLen = SignatureSize<G>;
type VerifyState<CS: CipherSuite, KE: Group> = PreHash<H>; type VerifyState<CS: CipherSuite, KE: Group> = PreHash<H>;
// We use a manual implementation of `RandomizedPrehashSigner` to use the same // We use a manual implementation of `RandomizedPrehashSigner` to use the same
// hash for the message as for generating `k`. See // hash for the message as for generating `k`. See
// https://github.com/RustCrypto/signatures/issues/949. // https://github.com/RustCrypto/signatures/issues/949.
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>( fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk, sk: &<Self::Group as Group>::Sk,
rng: &mut R, rng: &mut R,
message: &Message<CS, KE>, message: &Message<CS, KE>,
@@ -63,7 +57,7 @@ where
let hash = message.hash::<H>(); let hash = message.hash::<H>();
( (
Signature(sign::<_, G, H>(sk, rng, &hash.sign.finalize_fixed())), sign::<_, G, H>(sk, rng, &hash.sign.finalize_fixed()),
PreHash(hash.verify.finalize_fixed()), PreHash(hash.verify.finalize_fixed()),
) )
} }
@@ -74,96 +68,55 @@ where
state: Self::VerifyState<CS, KE>, state: Self::VerifyState<CS, KE>,
signature: &Self::Signature, signature: &Self::Signature,
) -> Result<(), ProtocolError> { ) -> Result<(), ProtocolError> {
verify(pk, &state.0, &signature.0) verify(pk, &state.0, signature)
} }
fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> { fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> {
signature.0.to_bytes() GenericArray::from_slice(signature.to_bytes().as_slice()).clone()
} }
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> { fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
ecdsa::Signature::from_bytes(&bytes.take_array("signature")?) ecdsa::Signature::from_bytes(&bytes.take_array("signature")?.into_ha0_4())
.map(Signature)
.map_err(|_| ProtocolError::SerializationError) .map_err(|_| ProtocolError::SerializationError)
} }
} }
fn sign<R, C, H>(sk: &SecretKey<C>, rng: &mut R, pre_hash: &[u8]) -> ecdsa::Signature<C> fn sign<R, C, H>(sk: &SecretKey<C>, rng: &mut R, pre_hash: &[u8]) -> ecdsa::Signature<C>
where where
R: CryptoRng + RngCore, R: CryptoRng + Rng,
C: CurveArithmetic + PrimeCurve, C: CurveArithmetic + EcdsaCurve,
SignatureSize<C>: ArrayLength<u8>, SignatureSize<C>: ArraySize,
H: Default + BlockSizeUser + FixedOutputReset<OutputSize = FieldBytesSize<C>> + HashMarker, H: Digest + BlockSizeUser + FixedOutputReset,
{ {
let repr = sk.to_bytes(); let mut ad = FieldBytes::<C>::default();
let order = C::ORDER.encode_field_bytes(); rng.fill_bytes(&mut ad);
let z = ecdsa::hazmat::sign_prehashed_rfc6979::<C, H>(&sk.to_nonzero_scalar(), pre_hash, &ad).0
hazmat::bits2field::<C>(pre_hash).expect("hash output can not be shorter than a scalar");
// This can only fail if the computed `r` or `s` are zero, in which case we just
// retry with a new `k`. See https://github.com/RustCrypto/signatures/pull/951.
loop {
let mut ad = FieldBytes::<C>::default();
rng.fill_bytes(&mut ad);
let k =
Scalar::<C>::from_repr(rfc6979::generate_k::<H, _>(&repr, &order, &z, &ad)).unwrap();
if let Ok((signature, _)) = hazmat::sign_prehashed::<C, _>(&sk.to_nonzero_scalar(), k, &z) {
break signature;
}
}
} }
fn verify<C>( fn verify<C>(
pk: &NonIdentity<C>, pk: &NonIdentity<ProjectivePoint<C>>,
pre_hash: &[u8], pre_hash: &[u8],
signature: &ecdsa::Signature<C>, signature: &ecdsa::Signature<C>,
) -> Result<(), ProtocolError> ) -> Result<(), ProtocolError>
where where
C: CurveArithmetic + PrimeCurve, C: CurveArithmetic + EcdsaCurve,
SignatureSize<C>: ArrayLength<u8>, SignatureSize<C>: ArraySize,
{ {
let z = ecdsa::hazmat::verify_prehashed(&pk.to_point(), pre_hash, signature)
hazmat::bits2field::<C>(pre_hash).expect("hash output can not be shorter than a scalar");
hazmat::verify_prehashed(&pk.0.to_point(), &z, signature)
.map_err(|_| ProtocolError::InvalidLoginError) .map_err(|_| ProtocolError::InvalidLoginError)
} }
/// Wrapper around [`ecdsa::Signature`] to implement [`Zeroize`].
// TODO: remove after https://github.com/RustCrypto/signatures/pull/948.
#[derive_where(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(bound = "", transparent)
)]
pub struct Signature<G: CurveArithmetic + PrimeCurve>(pub ecdsa::Signature<G>)
where
SignatureSize<G>: ArrayLength<u8>;
impl<G: CurveArithmetic + PrimeCurve> Zeroize for Signature<G>
where
SignatureSize<G>: ArrayLength<u8>,
{
fn zeroize(&mut self) {
self.0 = ecdsa::Signature::from_scalars(
Into::<FieldBytes<G>>::into(Scalar::<G>::ONE),
Into::<FieldBytes<G>>::into(Scalar::<G>::ONE),
)
.expect("failed to create `Signature` with non-zero `Scalar`s");
}
}
#[test] #[test]
fn ecdsa() { fn ecdsa() {
use std::vec; use std::vec;
use digest::Digest; use digest::Digest;
use p256::ecdsa::signature::{DigestVerifier, RandomizedDigestSigner}; use ecdsa::signature::hazmat::PrehashVerifier;
use p256::ecdsa::signature::RandomizedDigestSigner;
use p256::ecdsa::{Signature, SigningKey, VerifyingKey}; use p256::ecdsa::{Signature, SigningKey, VerifyingKey};
use p256::{NistP256, PublicKey}; use p256::{NistP256, PublicKey};
use rand::rngs::OsRng; use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use sha2::Sha256; use sha2::Sha256;
use crate::tests::mock_rng::CycleRng; use crate::tests::mock_rng::CycleRng;
@@ -171,22 +124,24 @@ fn ecdsa() {
let mut rng = CycleRng::new(vec![1; 32]); let mut rng = CycleRng::new(vec![1; 32]);
let mut message = [0; 1024]; let mut message = [0; 1024];
OsRng.fill_bytes(&mut message); UnwrapErr(SysRng).fill_bytes(&mut message);
let hash = Sha256::new_with_prefix(message); let hash = Sha256::new_with_prefix(message);
let sk = NistP256::random_sk(&mut OsRng); let sk = NistP256::random_sk(&mut UnwrapErr(SysRng));
let signing_key = SigningKey::from(sk.clone()); let signing_key = SigningKey::from(sk.clone());
let signature: Signature = signing_key.sign_digest_with_rng(&mut rng, hash.clone()); let signature: Signature = signing_key.sign_digest_with_rng(&mut rng, |d: &mut Sha256| {
d.update(message);
});
let custom_signature = sign::<_, _, Sha256>(&sk, &mut rng, &hash.clone().finalize()); let custom_signature = sign::<_, _, Sha256>(&sk, &mut rng, &hash.clone().finalize());
assert_eq!(signature, custom_signature); assert_eq!(signature, custom_signature);
let pk = NistP256::public_key(&sk); let pk = NistP256::public_key(&sk);
let verifying_key = VerifyingKey::from(PublicKey::from(pk.0)); let verifying_key = VerifyingKey::from(PublicKey::from(&pk));
verifying_key verifying_key
.verify_digest(hash.clone(), &signature) .verify_prehash(&hash.clone().finalize(), &signature)
.unwrap(); .unwrap();
verify(&pk, &hash.finalize(), &custom_signature).unwrap(); verify(&pk, &hash.finalize(), &custom_signature).unwrap();
} }
+3 -3
View File
@@ -12,7 +12,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use generic_array::GenericArray; use generic_array::GenericArray;
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use zeroize::Zeroize; use zeroize::Zeroize;
use self::implementation::HashEddsaImpl; use self::implementation::HashEddsaImpl;
@@ -33,7 +33,7 @@ impl<G: HashEddsaImpl> SignatureProtocol for HashEddsa<G> {
type SignatureLen = G::SignatureLen; type SignatureLen = G::SignatureLen;
type VerifyState<CS: CipherSuite, KE: Group> = G::VerifyState<CS, KE>; type VerifyState<CS: CipherSuite, KE: Group> = G::VerifyState<CS, KE>;
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>( fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk, sk: &<Self::Group as Group>::Sk,
_: &mut R, _: &mut R,
message: &Message<CS, KE>, message: &Message<CS, KE>,
@@ -66,7 +66,7 @@ pub(in super::super) mod implementation {
pub trait HashEddsaImpl: Group { pub trait HashEddsaImpl: Group {
type Signature: Clone + Zeroize; type Signature: Clone + Zeroize;
type SignatureLen: ArrayLength<u8>; type SignatureLen: ArrayLength;
type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize; type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize;
fn sign<CS: CipherSuite, KE: Group>( fn sign<CS: CipherSuite, KE: Group>(
+16 -17
View File
@@ -10,7 +10,6 @@ use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::{FixedOutput, Output, Update}; use digest::{FixedOutput, Output, Update};
use generic_array::sequence::Concat;
use generic_array::typenum::Sum; use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use zeroize::Zeroize; use zeroize::Zeroize;
@@ -26,7 +25,7 @@ use crate::key_exchange::{
SerializedIdentifier, SerializedIdentifiers, SerializedIdentifier, SerializedIdentifiers,
}; };
use crate::opaque::MaskedResponseLen; use crate::opaque::MaskedResponseLen;
use crate::serialization::{SliceExt, UpdateExt}; use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// This holds the message to be signed and the message to be verified. /// This holds the message to be signed and the message to be verified.
/// ///
@@ -242,7 +241,7 @@ impl<CS: CipherSuite, KE: Group> Deserialize for CachedMessage<CS, KE> {
credential_response: SerializedCredentialResponse::deserialize_take(input)?, credential_response: SerializedCredentialResponse::deserialize_take(input)?,
server_nonce: input.take_array("server nonce")?, server_nonce: input.take_array("server nonce")?,
server_e_pk: input.take_array("serialized server ephemeral key")?, server_e_pk: input.take_array("serialized server ephemeral key")?,
server_mac: input.take_array("server mac")?, server_mac: input.take_array("server mac")?.into_ha0_4(),
}) })
} }
} }
@@ -264,20 +263,20 @@ type CachedMessageLen<CS: CipherSuite, KE: Group> = Sum<
impl<CS: CipherSuite, KE: Group> Serialize for CachedMessage<CS, KE> impl<CS: CipherSuite, KE: Group> Serialize for CachedMessage<CS, KE>
where where
SerializedCredentialRequestLen<CS>: ArrayLength<u8> + Add<Ke1MessageIterLen<KE>>, SerializedCredentialRequestLen<CS>: ArrayLength + Add<Ke1MessageIterLen<KE>>,
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>: Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>:
ArrayLength<u8> + Add<SerializedCredentialResponseLen<CS>>, ArrayLength + Add<SerializedCredentialResponseLen<CS>>,
Sum< Sum<
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>, Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
SerializedCredentialResponseLen<CS>, SerializedCredentialResponseLen<CS>,
>: ArrayLength<u8> + Add<NonceLen>, >: ArrayLength + Add<NonceLen>,
Sum< Sum<
Sum< Sum<
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>, Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
SerializedCredentialResponseLen<CS>, SerializedCredentialResponseLen<CS>,
>, >,
NonceLen, NonceLen,
>: ArrayLength<u8> + Add<KE::PkLen>, >: ArrayLength + Add<KE::PkLen>,
Sum< Sum<
Sum< Sum<
Sum< Sum<
@@ -287,26 +286,26 @@ where
NonceLen, NonceLen,
>, >,
KE::PkLen, KE::PkLen,
>: ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>, >: ArrayLength + Add<OutputSize<KeHash<CS>>>,
CachedMessageLen<CS, KE>: ArrayLength<u8>, CachedMessageLen<CS, KE>: ArrayLength,
// Ke1MessageIter // Ke1MessageIter
NonceLen: Add<KE::PkLen>, NonceLen: Add<KE::PkLen>,
Ke1MessageIterLen<KE>: ArrayLength<u8>, Ke1MessageIterLen<KE>: ArrayLength,
// CredentialResponseParts // CredentialResponseParts
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
SerializedCredentialResponseLen<CS>: ArrayLength<u8>, SerializedCredentialResponseLen<CS>: ArrayLength,
{ {
type Len = CachedMessageLen<CS, KE>; type Len = CachedMessageLen<CS, KE>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.credential_request self.credential_request
.serialize() .serialize()
.concat(self.ke1_message.serialize()) .cat(self.ke1_message.serialize())
.concat(self.credential_response.serialize()) .cat(self.credential_response.serialize())
.concat(self.server_nonce) .cat(self.server_nonce)
.concat(self.server_e_pk.clone()) .cat(self.server_e_pk.clone())
.concat(self.server_mac.clone()) .cat(GenericArray::from_slice(self.server_mac.as_slice()).clone())
} }
} }
+75 -55
View File
@@ -23,13 +23,13 @@ use core::marker::PhantomData;
use core::ops::Add; use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::block_api::{BlockSizeUser, CoreProxy, SmallBlockSizeUser};
use digest::{Digest, Mac, Output, OutputSizeUser}; use digest::{Mac, Output, OutputSizeUser};
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256}; use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hmac::Hmac; use hmac::{KeyInit, SimpleHmac};
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption}; use subtle::{ConstantTimeEq, CtOption};
use zeroize::Zeroize; use zeroize::Zeroize;
@@ -49,7 +49,7 @@ pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
use crate::key_exchange::shared::{derive_keys, generate_ke1, generate_nonce, transcript}; use crate::key_exchange::shared::{derive_keys, generate_ke1, generate_nonce, transcript};
use crate::keypair::{KeyPair, PrivateKey, PublicKey}; use crate::keypair::{KeyPair, PrivateKey, PublicKey};
use crate::opaque::Identifiers; use crate::opaque::Identifiers;
use crate::serialization::{SliceExt, UpdateExt}; use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
/// The SIGMA-I key exchange implementation /// The SIGMA-I key exchange implementation
/// ///
@@ -95,7 +95,7 @@ pub trait SignatureProtocol {
/// The signature. /// The signature.
type Signature: Clone + Zeroize; type Signature: Clone + Zeroize;
/// Length of a serialized [`Signature`](Self::Signature). /// Length of a serialized [`Signature`](Self::Signature).
type SignatureLen: ArrayLength<u8>; type SignatureLen: ArrayLength;
/// The state required to run the verification. This is used to cache the /// The state required to run the verification. This is used to cache the
/// pre-hash for curves that support that, otherwise the [`Message`] to /// pre-hash for curves that support that, otherwise the [`Message`] to
/// verify is stored via [`CachedMessage`]. /// verify is stored via [`CachedMessage`].
@@ -111,7 +111,7 @@ pub trait SignatureProtocol {
/// The returned [`VerifyState`](Self::VerifyState) will be passed to /// The returned [`VerifyState`](Self::VerifyState) will be passed to
/// [`verify()`](Self::verify) and must contain the necessary /// [`verify()`](Self::verify) and must contain the necessary
/// information to verify the incoming signature. /// information to verify the incoming signature.
fn sign<R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>( fn sign<R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &<Self::Group as Group>::Sk, sk: &<Self::Group as Group>::Sk,
rng: &mut R, rng: &mut R,
message: &Message<CS, KE>, message: &Message<CS, KE>,
@@ -202,8 +202,9 @@ pub struct Ke2State<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> {
pub struct Ke2Message<SIG: SignatureProtocol, KE: Group, KEH: Hash> pub struct Ke2Message<SIG: SignatureProtocol, KE: Group, KEH: Hash>
where where
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{ {
server_nonce: GenericArray<u8, NonceLen>, server_nonce: GenericArray<u8, NonceLen>,
#[derive_where(skip(Zeroize))] #[derive_where(skip(Zeroize))]
@@ -223,37 +224,42 @@ where
)] )]
#[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Clone, ZeroizeOnDrop)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; SIG::Signature)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; SIG::Signature)]
pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser> { pub struct Ke3Message<SIG: SignatureProtocol, KEH: OutputSizeUser>
where
<KEH as OutputSizeUser>::OutputSize: ArrayLength,
{
signature: SIG::Signature, signature: SIG::Signature,
mac: Output<KEH>, mac: Output<KEH>,
} }
impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash> KeyExchange for SigmaI<SIG, KE, KEH> impl<SIG: SignatureProtocol, KE: 'static + Group, KEH: Hash + BlockSizeUser> KeyExchange
for SigmaI<SIG, KE, KEH>
where where
KE::Sk: DiffieHellman<KE>, KE::Sk: DiffieHellman<KE>,
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{ {
type Group = SIG::Group; type Group = SIG::Group;
type Hash = KEH; type Hash = KEH;
type KE1State = Ke1State<KE>; type KE1State = Ke1State<KE>;
type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
type KE1Message = Ke1Message<KE>; type KE1Message = Ke1Message<KE>;
type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'a, CS, KE>; type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'a, CS, KE>;
type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>; type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>;
type KE2BuilderInput<CS: CipherSuite> = (SIG::Signature, SIG::VerifyState<CS, KE>); type KE2BuilderInput<CS: CipherSuite> = (SIG::Signature, SIG::VerifyState<CS, KE>);
type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
type KE2Message = Ke2Message<SIG, KE, KEH>; type KE2Message = Ke2Message<SIG, KE, KEH>;
type KE3Message = Ke3Message<SIG, KEH>; type KE3Message = Ke3Message<SIG, KEH>;
fn generate_ke1<R: RngCore + CryptoRng>( fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> { ) -> Result<GenerateKe1Result<Self>, ProtocolError> {
generate_ke1(rng) generate_ke1(rng)
} }
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>( fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -287,13 +293,13 @@ where
&transcript_hasher.finalize(), &transcript_hasher.finalize(),
)?; )?;
let mut server_mac = let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; .map_err(|_| InternalError::HmacError)?;
server_mac.update_iter(identifiers.server.iter()); server_mac.update_iter(identifiers.server.iter());
let server_mac = server_mac.finalize().into_bytes(); let server_mac = server_mac.finalize().into_bytes();
let mut client_mac = let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; .map_err(|_| InternalError::HmacError)?;
client_mac.update_iter(identifiers.client.iter()); client_mac.update_iter(identifiers.client.iter());
let client_mac = client_mac.finalize().into_bytes(); let client_mac = client_mac.finalize().into_bytes();
@@ -331,7 +337,7 @@ where
&builder.transcript &builder.transcript
} }
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>, builder: &Self::KE2Builder<'_, CS>,
rng: &mut R, rng: &mut R,
server_s_sk: &PrivateKey<Self::Group>, server_s_sk: &PrivateKey<Self::Group>,
@@ -363,7 +369,7 @@ where
}) })
} }
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -397,8 +403,8 @@ where
&transcript_hasher.finalize(), &transcript_hasher.finalize(),
)?; )?;
let mut server_mac = let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; .map_err(|_| InternalError::HmacError)?;
server_mac.update_iter(identifiers.server.iter()); server_mac.update_iter(identifiers.server.iter());
let server_mac = server_mac.finalize().into_bytes(); let server_mac = server_mac.finalize().into_bytes();
@@ -406,8 +412,8 @@ where
.then_some(()) .then_some(())
.ok_or(ProtocolError::InvalidLoginError)?; .ok_or(ProtocolError::InvalidLoginError)?;
let mut client_mac = let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; .map_err(|_| InternalError::HmacError)?;
client_mac.update_iter(identifiers.client.iter()); client_mac.update_iter(identifiers.client.iter());
let client_mac = client_mac.finalize().into_bytes(); let client_mac = client_mac.finalize().into_bytes();
@@ -481,13 +487,14 @@ where
impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Deserialize for Ke2State<CS, SIG, KE> impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Deserialize for Ke2State<CS, SIG, KE>
where where
SIG::VerifyState<CS, KE>: Deserialize, SIG::VerifyState<CS, KE>: Deserialize,
OutputSize<KeHash<CS>>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
client_s_pk: PublicKey::deserialize_take(input)?, client_s_pk: PublicKey::deserialize_take(input)?,
session_key: input.take_array("session key")?, session_key: input.take_array("session key")?.into_ha0_4(),
verify_state: SIG::VerifyState::deserialize_take(input)?, verify_state: SIG::VerifyState::<CS, KE>::deserialize_take(input)?,
expected_mac: input.take_array("expected mac")?, expected_mac: input.take_array("expected mac")?.into_ha0_4(),
}) })
} }
} }
@@ -502,37 +509,44 @@ type VerifyStateLen<CS, SIG: SignatureProtocol, KE> = <SIG::VerifyState<CS, KE>
impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Serialize for Ke2State<CS, SIG, KE> impl<CS: CipherSuite, SIG: SignatureProtocol, KE: Group> Serialize for Ke2State<CS, SIG, KE>
where where
SIG::VerifyState<CS, KE>: Serialize, SIG::VerifyState<CS, KE>: Serialize,
OutputSize<KeHash<CS>>: ArrayLength,
// Ke2State: ((SigPk + Hash) + VerifyState) + Hash // Ke2State: ((SigPk + Hash) + VerifyState) + Hash
<SIG::Group as Group>::PkLen: Add<OutputSize<KeHash<CS>>>, <SIG::Group as Group>::PkLen: Add<OutputSize<KeHash<CS>>>,
Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>: Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>:
ArrayLength<u8> + Add<VerifyStateLen<CS, SIG, KE>>, ArrayLength + Add<VerifyStateLen<CS, SIG, KE>>,
Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>: Sum<Sum<<SIG::Group as Group>::PkLen, OutputSize<KeHash<CS>>>, VerifyStateLen<CS, SIG, KE>>:
ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>, ArrayLength + Add<OutputSize<KeHash<CS>>>,
Ke2StateLen<CS, SIG, KE>: ArrayLength<u8>, Ke2StateLen<CS, SIG, KE>: ArrayLength,
{ {
type Len = Ke2StateLen<CS, SIG, KE>; type Len = Ke2StateLen<CS, SIG, KE>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.client_s_pk Concat::concat(
.serialize() Concat::concat(
.concat(self.session_key.clone()) Concat::concat(
.concat(self.verify_state.serialize()) self.client_s_pk.serialize(),
.concat(self.expected_mac.clone()) GenericArray::from_slice(self.session_key.as_slice()).clone(),
),
self.verify_state.serialize(),
),
GenericArray::from_slice(self.expected_mac.as_slice()).clone(),
)
} }
} }
impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Deserialize for Ke2Message<SIG, KE, KEH> impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Deserialize for Ke2Message<SIG, KE, KEH>
where where
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
server_nonce: input.take_array("server nonce")?, server_nonce: input.take_array("server nonce")?,
server_e_pk: PublicKey::deserialize_take(input)?, server_e_pk: PublicKey::deserialize_take(input)?,
signature: SIG::deserialize_take_signature(input)?, signature: SIG::deserialize_take_signature(input)?,
mac: input.take_array("mac")?, mac: input.take_array("mac")?.into_ha0_4(),
}) })
} }
} }
@@ -540,34 +554,36 @@ where
impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Serialize for Ke2Message<SIG, KE, KEH> impl<SIG: SignatureProtocol, KE: Group, KEH: Hash> Serialize for Ke2Message<SIG, KE, KEH>
where where
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
// Ke2Message: ((Nonce + KePk) + Signature) + Hash // Ke2Message: ((Nonce + KePk) + Signature) + Hash
NonceLen: Add<KE::PkLen>, NonceLen: Add<KE::PkLen>,
Sum<NonceLen, KE::PkLen>: ArrayLength<u8> + Add<SIG::SignatureLen>, Sum<NonceLen, KE::PkLen>: ArrayLength + Add<SIG::SignatureLen>,
Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength<u8> + Add<OutputSize<KEH>>, Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength + Add<OutputSize<KEH>>,
Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength<u8>, Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength,
{ {
type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>; type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.server_nonce self.server_nonce
.concat(self.server_e_pk.serialize()) .cat(self.server_e_pk.serialize())
.concat(SIG::serialize_signature(&self.signature)) .cat(SIG::serialize_signature(&self.signature))
.concat(self.mac.clone()) .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
} }
} }
impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH> impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH>
where where
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
signature: SIG::deserialize_take_signature(input)?, signature: SIG::deserialize_take_signature(input)?,
mac: input.take_array("mac")?, mac: input.take_array("mac")?.into_ha0_4(),
}) })
} }
} }
@@ -575,15 +591,19 @@ where
impl<SIG: SignatureProtocol, KEH: Hash> Serialize for Ke3Message<SIG, KEH> impl<SIG: SignatureProtocol, KEH: Hash> Serialize for Ke3Message<SIG, KEH>
where where
KEH::Core: ProxyHash, KEH::Core: ProxyHash,
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<KEH>: ArrayLength,
// Ke2Message: Signature + Hash // Ke2Message: Signature + Hash
SIG::SignatureLen: Add<OutputSize<KEH>>, SIG::SignatureLen: Add<OutputSize<KEH>>,
Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength<u8>, Sum<SIG::SignatureLen, OutputSize<KEH>>: ArrayLength,
{ {
type Len = Sum<SIG::SignatureLen, OutputSize<KEH>>; type Len = Sum<SIG::SignatureLen, OutputSize<KEH>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
SIG::serialize_signature(&self.signature).concat(self.mac.clone()) Concat::concat(
SIG::serialize_signature(&self.signature),
GenericArray::from_slice(self.mac.as_slice()).clone(),
)
} }
} }
+7 -7
View File
@@ -12,7 +12,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use generic_array::GenericArray; use generic_array::GenericArray;
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use zeroize::Zeroize; use zeroize::Zeroize;
use self::implementation::PureEddsaImpl; use self::implementation::PureEddsaImpl;
@@ -34,7 +34,7 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
type SignatureLen = G::SignatureLen; type SignatureLen = G::SignatureLen;
type VerifyState<CS: CipherSuite, KE: Group> = CachedMessage<CS, KE>; type VerifyState<CS: CipherSuite, KE: Group> = CachedMessage<CS, KE>;
fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>( fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>(
sk: &G::Sk, sk: &G::Sk,
_: &mut R, _: &mut R,
message: &Message<CS, KE>, message: &Message<CS, KE>,
@@ -51,13 +51,13 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
G::verify(pk, message_builder, state, signature) G::verify(pk, message_builder, state, signature)
} }
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
G::deserialize_take_signature(bytes)
}
fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> { fn serialize_signature(signature: &Self::Signature) -> GenericArray<u8, Self::SignatureLen> {
G::serialize_signature(signature) G::serialize_signature(signature)
} }
fn deserialize_take_signature(bytes: &mut &[u8]) -> Result<Self::Signature, ProtocolError> {
G::deserialize_take_signature(bytes)
}
} }
pub(in super::super) mod implementation { pub(in super::super) mod implementation {
@@ -67,7 +67,7 @@ pub(in super::super) mod implementation {
pub trait PureEddsaImpl: Group { pub trait PureEddsaImpl: Group {
type Signature: Clone + Zeroize; type Signature: Clone + Zeroize;
type SignatureLen: ArrayLength<u8>; type SignatureLen: ArrayLength;
fn sign<CS: CipherSuite, KE: Group>( fn sign<CS: CipherSuite, KE: Group>(
sk: &Self::Sk, sk: &Self::Sk,
+11 -5
View File
@@ -16,24 +16,30 @@ use crate::serialization::SliceExt;
/// Pre-hash of the message to be verified. /// Pre-hash of the message to be verified.
#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)] #[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
#[derive_where(Copy; <H::OutputSize as ArrayLength<u8>>::ArrayType)]
#[cfg_attr( #[cfg_attr(
feature = "serde", feature = "serde",
derive(serde::Deserialize, serde::Serialize), derive(serde::Deserialize, serde::Serialize),
serde(bound = "") serde(bound = "")
)] )]
#[allow(dead_code)]
pub struct PreHash<H: OutputSizeUser>(pub Output<H>); pub struct PreHash<H: OutputSizeUser>(pub Output<H>);
impl<H: OutputSizeUser> Deserialize for PreHash<H> { impl<H: OutputSizeUser> Deserialize for PreHash<H>
where
H::OutputSize: ArrayLength,
{
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self(input.take_array("pre-hash")?)) Ok(Self(input.take_array("pre-hash")?.into_ha0_4()))
} }
} }
impl<H: OutputSizeUser> Serialize for PreHash<H> { impl<H: OutputSizeUser> Serialize for PreHash<H>
where
H::OutputSize: ArrayLength,
{
type Len = H::OutputSize; type Len = H::OutputSize;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone() GenericArray::from_slice(self.0.as_slice()).clone()
} }
} }
+62 -47
View File
@@ -12,12 +12,11 @@ use core::marker::PhantomData;
use core::ops::Add; use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use digest::{Digest, Output, OutputSizeUser}; use digest::{Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256}; use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption}; use subtle::{ConstantTimeEq, CtOption};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -34,7 +33,7 @@ use crate::key_exchange::shared::{self, NonceLen};
pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State}; pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
use crate::keypair::{PrivateKey, PublicKey}; use crate::keypair::{PrivateKey, PublicKey};
use crate::opaque::Identifiers; use crate::opaque::Identifiers;
use crate::serialization::SliceExt; use crate::serialization::{ConcatExt, SliceExt};
//////////////////////////// ////////////////////////////
// High-level API Structs // // High-level API Structs //
@@ -79,8 +78,9 @@ pub struct Ke2State<H: OutputSizeUser> {
pub struct Ke2Builder<G: Group, H: Hash> pub struct Ke2Builder<G: Group, H: Hash>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
server_nonce: GenericArray<u8, NonceLen>, server_nonce: GenericArray<u8, NonceLen>,
transcript_hasher: H, transcript_hasher: H,
@@ -104,8 +104,9 @@ where
pub struct Ke2Message<G: Group, H: Hash> pub struct Ke2Message<G: Group, H: Hash>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
pub(super) server_nonce: GenericArray<u8, NonceLen>, pub(super) server_nonce: GenericArray<u8, NonceLen>,
#[derive_where(skip(Zeroize))] #[derive_where(skip(Zeroize))]
@@ -123,8 +124,9 @@ where
pub struct Ke3Message<H: Hash> pub struct Ke3Message<H: Hash>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
pub(super) mac: Output<H>, pub(super) mac: Output<H>,
} }
@@ -138,8 +140,9 @@ impl<G: Group + 'static, H: Hash> KeyExchange for TripleDh<G, H>
where where
G::Sk: DiffieHellman<G>, G::Sk: DiffieHellman<G>,
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
type Group = G; type Group = G;
type Hash = H; type Hash = H;
@@ -153,13 +156,13 @@ where
type KE2Message = Ke2Message<G, H>; type KE2Message = Ke2Message<G, H>;
type KE3Message = Ke3Message<H>; type KE3Message = Ke3Message<H>;
fn generate_ke1<R: RngCore + CryptoRng>( fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> { ) -> Result<GenerateKe1Result<Self>, ProtocolError> {
shared::generate_ke1(rng) shared::generate_ke1(rng)
} }
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>( fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -201,7 +204,7 @@ where
&builder.client_e_pk &builder.client_e_pk
} }
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>, builder: &Self::KE2Builder<'_, CS>,
_: &mut R, _: &mut R,
server_s_sk: &PrivateKey<G>, server_s_sk: &PrivateKey<G>,
@@ -247,7 +250,7 @@ where
}) })
} }
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
_: &mut R, _: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -319,13 +322,14 @@ where
impl<H: Hash> Deserialize for Ke2State<H> impl<H: Hash> Deserialize for Ke2State<H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
session_key: input.take_array("session key")?, session_key: input.take_array("session key")?.into_ha0_4(),
expected_mac: input.take_array("expected mac")?, expected_mac: input.take_array("expected mac")?.into_ha0_4(),
}) })
} }
} }
@@ -333,26 +337,32 @@ where
impl<H: Hash> Serialize for Ke2State<H> impl<H: Hash> Serialize for Ke2State<H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
// Ke2State: Hash + Hash // Ke2State: Hash + Hash
OutputSize<H>: Add<OutputSize<H>>, OutputSize<H>: Add<OutputSize<H>>,
Sum<OutputSize<H>, OutputSize<H>>: ArrayLength<u8>, Sum<OutputSize<H>, OutputSize<H>>: ArrayLength,
{ {
type Len = Sum<OutputSize<H>, OutputSize<H>>; type Len = Sum<OutputSize<H>, OutputSize<H>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.session_key.clone().concat(self.expected_mac.clone()) let sk: GenericArray<u8, OutputSize<H>> =
GenericArray::from_slice(self.session_key.as_slice()).clone();
let mac: GenericArray<u8, OutputSize<H>> =
GenericArray::from_slice(self.expected_mac.as_slice()).clone();
sk.cat(mac)
} }
} }
/// TODO: implement via derive after hash crates get `Zeroize` support in /// TODO: implement via derive after `Hash` gets `Zeroize` support.
/// `digest` v11.
impl<G: Group, H: Hash> Drop for Ke2Builder<G, H> impl<G: Group, H: Hash> Drop for Ke2Builder<G, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
fn drop(&mut self) { fn drop(&mut self) {
let Self { let Self {
@@ -365,7 +375,7 @@ where
} = self; } = self;
server_nonce.zeroize(); server_nonce.zeroize();
transcript_hasher.reset(); digest::Reset::reset(transcript_hasher);
shared_secret_1.zeroize(); shared_secret_1.zeroize();
shared_secret_3.zeroize(); shared_secret_3.zeroize();
} }
@@ -374,22 +384,24 @@ where
impl<G: Group, H: Hash> ZeroizeOnDrop for Ke2Builder<G, H> impl<G: Group, H: Hash> ZeroizeOnDrop for Ke2Builder<G, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
} }
impl<G: Group, H: Hash> Deserialize for Ke2Message<G, H> impl<G: Group, H: Hash> Deserialize for Ke2Message<G, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
server_nonce: input.take_array("server nonce")?, server_nonce: input.take_array("server nonce")?,
server_e_pk: PublicKey::deserialize_take(input)?, server_e_pk: PublicKey::deserialize_take(input)?,
mac: input.take_array("mac")?, mac: input.take_array("mac")?.into_ha0_4(),
}) })
} }
} }
@@ -397,31 +409,33 @@ where
impl<H: Hash, G: Group> Serialize for Ke2Message<G, H> impl<H: Hash, G: Group> Serialize for Ke2Message<G, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
// Ke2Message: (Nonce + KePk) + Hash // Ke2Message: (Nonce + KePk) + Hash
NonceLen: Add<G::PkLen>, NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>, Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>, Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
{ {
type Len = Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>; type Len = Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.server_nonce self.server_nonce
.concat(self.server_e_pk.serialize()) .cat(self.server_e_pk.serialize())
.concat(self.mac.clone()) .cat(GenericArray::from_slice(self.mac.as_slice()).clone())
} }
} }
impl<H: Hash> Deserialize for Ke3Message<H> impl<H: Hash> Deserialize for Ke3Message<H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
mac: bytes.take_array("mac")?, mac: bytes.take_array("mac")?.into_ha0_4(),
}) })
} }
} }
@@ -429,12 +443,13 @@ where
impl<H: Hash> Serialize for Ke3Message<H> impl<H: Hash> Serialize for Ke3Message<H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
OutputSize<H>: ArrayLength,
{ {
type Len = OutputSize<H>; type Len = OutputSize<H>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.mac.clone() GenericArray::from_slice(self.mac.as_slice()).clone()
} }
} }
+96 -69
View File
@@ -23,18 +23,18 @@ use core::marker::PhantomData;
use core::ops::Add; use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::Output;
use digest::{Digest, Output}; use digest::block_api::{CoreProxy, SmallBlockSizeUser};
use generic_array::sequence::Concat; use generic_array::typenum::{Cmp, IsLess, Le, NonZero, Sum, U256};
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hybrid_array::ArraySize;
#[allow(deprecated)] #[allow(deprecated)]
use ml_kem::ExpandedKeyEncoding; use ml_kem::ExpandedKeyEncoding;
use ml_kem::kem::{ use ml_kem::kem::{
Ciphertext as MlKemCiphertext, Decapsulate, Encapsulate, Kem as MlKemTrait, KeyExport, Ciphertext as MlKemCiphertext, Decapsulate, Encapsulate, Kem as MlKemTrait, KeyExport,
KeySizeUser, TryKeyInit, KeySizeUser, TryKeyInit,
}; };
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use subtle::{ConstantTimeEq, CtOption}; use subtle::{ConstantTimeEq, CtOption};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -50,7 +50,7 @@ use crate::hash::{Hash, OutputSize, ProxyHash};
use crate::key_exchange::group::Group; use crate::key_exchange::group::Group;
use crate::keypair::{PrivateKey, PublicKey}; use crate::keypair::{PrivateKey, PublicKey};
use crate::opaque::Identifiers; use crate::opaque::Identifiers;
use crate::serialization::SliceExt; use crate::serialization::{ConcatExt, SliceExt};
/// Adapter trait that augments the `ml-kem` core traits with the metadata /// Adapter trait that augments the `ml-kem` core traits with the metadata
/// required by OPAQUE (e.g. fixed lengths and serialization hooks). /// required by OPAQUE (e.g. fixed lengths and serialization hooks).
@@ -62,16 +62,16 @@ pub trait KemCoreWrapper {
type DecapsulationKey: Clone + ZeroizeOnDrop; type DecapsulationKey: Clone + ZeroizeOnDrop;
/// Length (in bytes) of the serialized public key. /// Length (in bytes) of the serialized public key.
type EncapsulationKeyLen: ArrayLength<u8>; type EncapsulationKeyLen: ArrayLength + ArraySize;
/// Length (in bytes) of the serialized secret key. /// Length (in bytes) of the serialized secret key.
type DecapsulationKeyLen: ArrayLength<u8>; type DecapsulationKeyLen: ArrayLength + ArraySize;
/// Length (in bytes) of the encapsulated ciphertext. /// Length (in bytes) of the encapsulated ciphertext.
type CiphertextLen: ArrayLength<u8>; type CiphertextLen: ArrayLength + ArraySize;
/// Length (in bytes) of the shared secret output by the KEM. /// Length (in bytes) of the shared secret output by the KEM.
type SharedSecretLen: ArrayLength<u8>; type SharedSecretLen: ArrayLength + ArraySize;
/// Generates a fresh KEM key pair. /// Generates a fresh KEM key pair.
fn generate<R: RngCore + CryptoRng>( fn generate<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError>; ) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError>;
@@ -98,7 +98,7 @@ pub trait KemCoreWrapper {
/// Encapsulates to the given public key, returning the ciphertext and /// Encapsulates to the given public key, returning the ciphertext and
/// shared secret. /// shared secret.
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn encapsulate<R: RngCore + CryptoRng>( fn encapsulate<R: Rng + CryptoRng>(
key: &Self::EncapsulationKey, key: &Self::EncapsulationKey,
rng: &mut R, rng: &mut R,
) -> Result< ) -> Result<
@@ -120,7 +120,7 @@ pub trait KemCoreWrapper {
/// which is required by `ml-kem 0.3.x`. /// which is required by `ml-kem 0.3.x`.
struct RngCompat<'a, R>(&'a mut R); struct RngCompat<'a, R>(&'a mut R);
impl<R: RngCore> rand_core_10::TryRng for RngCompat<'_, R> { impl<R: Rng> rand_core::TryRng for RngCompat<'_, R> {
type Error = core::convert::Infallible; type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> { fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
@@ -137,7 +137,7 @@ impl<R: RngCore> rand_core_10::TryRng for RngCompat<'_, R> {
} }
} }
impl<R: RngCore + CryptoRng> rand_core_10::TryCryptoRng for RngCompat<'_, R> {} impl<R: Rng + CryptoRng> rand_core::TryCryptoRng for RngCompat<'_, R> {}
type RcEncapsulationKeyLen<K> = <<K as MlKemTrait>::EncapsulationKey as KeySizeUser>::KeySize; type RcEncapsulationKeyLen<K> = <<K as MlKemTrait>::EncapsulationKey as KeySizeUser>::KeySize;
#[allow(deprecated)] #[allow(deprecated)]
@@ -152,10 +152,10 @@ where
K: MlKemTrait, K: MlKemTrait,
K::EncapsulationKey: Encapsulate<Kem = K> + KeyExport + TryKeyInit + Clone, K::EncapsulationKey: Encapsulate<Kem = K> + KeyExport + TryKeyInit + Clone,
K::DecapsulationKey: Decapsulate<Kem = K> + ExpandedKeyEncoding + Clone + ZeroizeOnDrop, K::DecapsulationKey: Decapsulate<Kem = K> + ExpandedKeyEncoding + Clone + ZeroizeOnDrop,
RcEncapsulationKeyLen<K>: ArrayLength<u8>, RcEncapsulationKeyLen<K>: ArrayLength + ArraySize,
RcDecapsulationKeyLen<K>: ArrayLength<u8>, RcDecapsulationKeyLen<K>: ArrayLength + ArraySize,
RcCiphertextLen<K>: ArrayLength<u8>, RcCiphertextLen<K>: ArrayLength + ArraySize,
RcSharedSecretLen<K>: ArrayLength<u8>, RcSharedSecretLen<K>: ArrayLength + ArraySize,
{ {
type EncapsulationKey = K::EncapsulationKey; type EncapsulationKey = K::EncapsulationKey;
type DecapsulationKey = K::DecapsulationKey; type DecapsulationKey = K::DecapsulationKey;
@@ -164,7 +164,7 @@ where
type CiphertextLen = RcCiphertextLen<K>; type CiphertextLen = RcCiphertextLen<K>;
type SharedSecretLen = RcSharedSecretLen<K>; type SharedSecretLen = RcSharedSecretLen<K>;
fn generate<R: RngCore + CryptoRng>( fn generate<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> { ) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> {
Ok(K::generate_keypair_from_rng(&mut RngCompat(rng))) Ok(K::generate_keypair_from_rng(&mut RngCompat(rng)))
@@ -173,7 +173,7 @@ where
fn serialize_encapsulation_key( fn serialize_encapsulation_key(
key: &Self::EncapsulationKey, key: &Self::EncapsulationKey,
) -> GenericArray<u8, Self::EncapsulationKeyLen> { ) -> GenericArray<u8, Self::EncapsulationKeyLen> {
GenericArray::clone_from_slice(key.to_bytes().as_slice()) GenericArray::from_slice(key.to_bytes().as_slice()).clone()
} }
fn deserialize_encapsulation_key( fn deserialize_encapsulation_key(
@@ -189,7 +189,7 @@ where
fn serialize_decapsulation_key( fn serialize_decapsulation_key(
key: &Self::DecapsulationKey, key: &Self::DecapsulationKey,
) -> GenericArray<u8, Self::DecapsulationKeyLen> { ) -> GenericArray<u8, Self::DecapsulationKeyLen> {
GenericArray::clone_from_slice(key.to_expanded_bytes().as_slice()) GenericArray::from_slice(key.to_expanded_bytes().as_slice()).clone()
} }
fn deserialize_decapsulation_key( fn deserialize_decapsulation_key(
@@ -203,7 +203,7 @@ where
.map_err(|_| ProtocolError::SerializationError) .map_err(|_| ProtocolError::SerializationError)
} }
fn encapsulate<R: RngCore + CryptoRng>( fn encapsulate<R: Rng + CryptoRng>(
key: &Self::EncapsulationKey, key: &Self::EncapsulationKey,
rng: &mut R, rng: &mut R,
) -> Result< ) -> Result<
@@ -215,8 +215,8 @@ where
> { > {
let (ciphertext, shared) = key.encapsulate_with_rng(&mut RngCompat(rng)); let (ciphertext, shared) = key.encapsulate_with_rng(&mut RngCompat(rng));
Ok(( Ok((
GenericArray::clone_from_slice(ciphertext.as_slice()), GenericArray::from_slice(ciphertext.as_slice()).clone(),
GenericArray::clone_from_slice(shared.as_slice()), GenericArray::from_slice(shared.as_slice()).clone(),
)) ))
} }
@@ -227,7 +227,7 @@ where
let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice()) let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice())
.map_err(|_| ProtocolError::SerializationError)?; .map_err(|_| ProtocolError::SerializationError)?;
let shared = key.decapsulate(&ciphertext); let shared = key.decapsulate(&ciphertext);
Ok(GenericArray::clone_from_slice(shared.as_slice())) Ok(GenericArray::from_slice(shared.as_slice()).clone())
} }
} }
/// Triple Diffie-Hellman-style key exchange that offloads the second hop to a /// Triple Diffie-Hellman-style key exchange that offloads the second hop to a
@@ -281,8 +281,10 @@ pub struct KemKe1Message<G: Group, K: KemCoreWrapper> {
pub struct KemKe2State<K: KemCoreWrapper, H: Hash> pub struct KemKe2State<K: KemCoreWrapper, H: Hash>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{ {
base_state: super::tripledh::Ke2State<H>, base_state: super::tripledh::Ke2State<H>,
kem_encapsulation_key: GenericArray<u8, K::EncapsulationKeyLen>, kem_encapsulation_key: GenericArray<u8, K::EncapsulationKeyLen>,
@@ -295,8 +297,10 @@ where
pub struct KemKe2Builder<G: Group, H: Hash, K: KemCoreWrapper> pub struct KemKe2Builder<G: Group, H: Hash, K: KemCoreWrapper>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{ {
server_nonce: GenericArray<u8, NonceLen>, server_nonce: GenericArray<u8, NonceLen>,
transcript_hasher: H, transcript_hasher: H,
@@ -323,8 +327,10 @@ where
pub struct KemKe2Message<G: Group, H: Hash, K: KemCoreWrapper> pub struct KemKe2Message<G: Group, H: Hash, K: KemCoreWrapper>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{ {
dh_message: super::tripledh::Ke2Message<G, H>, dh_message: super::tripledh::Ke2Message<G, H>,
kem_ciphertext: GenericArray<u8, K::CiphertextLen>, kem_ciphertext: GenericArray<u8, K::CiphertextLen>,
@@ -338,13 +344,15 @@ where
G: Group, G: Group,
H: Hash, H: Hash,
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper, K: KemCoreWrapper,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.server_nonce.zeroize(); self.server_nonce.zeroize();
self.transcript_hasher.reset(); digest::Digest::reset(&mut self.transcript_hasher);
self.shared_secret_1.zeroize(); self.shared_secret_1.zeroize();
self.shared_secret_3.zeroize(); self.shared_secret_3.zeroize();
self.kem_shared_secret.zeroize(); self.kem_shared_secret.zeroize();
@@ -357,8 +365,10 @@ where
G: Group, G: Group,
H: Hash, H: Hash,
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper, K: KemCoreWrapper,
{ {
} }
@@ -369,11 +379,13 @@ where
G::Sk: shared::DiffieHellman<G>, G::Sk: shared::DiffieHellman<G>,
H: Hash, H: Hash,
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
K: KemCoreWrapper, K: KemCoreWrapper,
NonceLen: Add<K::EncapsulationKeyLen>, NonceLen: Add<K::EncapsulationKeyLen>,
Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength<u8>, Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength,
{ {
type Group = G; type Group = G;
type Hash = H; type Hash = H;
@@ -390,7 +402,7 @@ where
type KE2Message = KemKe2Message<G, H, K>; type KE2Message = KemKe2Message<G, H, K>;
type KE3Message = KemKe3Message<H>; type KE3Message = KemKe3Message<H>;
fn generate_ke1<R: RngCore + CryptoRng>( fn generate_ke1<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
) -> Result<GenerateKe1Result<Self>, ProtocolError> { ) -> Result<GenerateKe1Result<Self>, ProtocolError> {
let base = super::tripledh::TripleDh::<G, H>::generate_ke1(rng)?; let base = super::tripledh::TripleDh::<G, H>::generate_ke1(rng)?;
@@ -409,7 +421,7 @@ where
}) })
} }
fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: RngCore + CryptoRng>( fn ke2_builder<'a, CS: CipherSuite<KeyExchange = Self>, R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -440,8 +452,11 @@ where
let (kem_ciphertext, kem_shared_secret) = K::encapsulate(&encapsulation_key, rng)?; let (kem_ciphertext, kem_shared_secret) = K::encapsulate(&encapsulation_key, rng)?;
let mut transcript_hasher = transcript_hasher; let mut transcript_hasher = transcript_hasher;
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice()); digest::Digest::update(
transcript_hasher.update(kem_ciphertext.as_slice()); &mut transcript_hasher,
ke1_message.kem_encapsulation_key.as_slice(),
);
digest::Digest::update(&mut transcript_hasher, kem_ciphertext.as_slice());
Ok(KemKe2Builder { Ok(KemKe2Builder {
server_nonce, server_nonce,
@@ -462,7 +477,7 @@ where
(&builder.client_e_pk, &builder.kem_encapsulation_key) (&builder.client_e_pk, &builder.kem_encapsulation_key)
} }
fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke2_input<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
builder: &Self::KE2Builder<'_, CS>, builder: &Self::KE2Builder<'_, CS>,
_: &mut R, _: &mut R,
server_s_sk: &PrivateKey<G>, server_s_sk: &PrivateKey<G>,
@@ -516,7 +531,7 @@ where
}) })
} }
fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + RngCore>( fn generate_ke3<CS: CipherSuite<KeyExchange = Self>, R: CryptoRng + Rng>(
_rng: &mut R, _rng: &mut R,
credential_request: SerializedCredentialRequest<CS>, credential_request: SerializedCredentialRequest<CS>,
ke1_message: Self::KE1Message, ke1_message: Self::KE1Message,
@@ -537,8 +552,14 @@ where
ke2_message.dh_message.server_nonce, ke2_message.dh_message.server_nonce,
&ke2_message.dh_message.server_e_pk.serialize(), &ke2_message.dh_message.server_e_pk.serialize(),
); );
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice()); digest::Digest::update(
transcript_hasher.update(ke2_message.kem_ciphertext.as_slice()); &mut transcript_hasher,
ke1_message.kem_encapsulation_key.as_slice(),
);
digest::Digest::update(
&mut transcript_hasher,
ke2_message.kem_ciphertext.as_slice(),
);
let shared_secret_1 = ke1_state let shared_secret_1 = ke1_state
.dh_state .dh_state
@@ -606,14 +627,14 @@ impl<G: Group, K: KemCoreWrapper> Serialize for KemKe1State<G, K>
where where
Ke1State<G>: Serialize, Ke1State<G>: Serialize,
<Ke1State<G> as Serialize>::Len: Add<K::DecapsulationKeyLen>, <Ke1State<G> as Serialize>::Len: Add<K::DecapsulationKeyLen>,
Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength<u8>, Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength,
{ {
type Len = Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>; type Len = Sum<<Ke1State<G> as Serialize>::Len, K::DecapsulationKeyLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_state self.dh_state
.serialize() .serialize()
.concat(K::serialize_decapsulation_key(&self.kem_decapsulation_key)) .cat(K::serialize_decapsulation_key(&self.kem_decapsulation_key))
} }
} }
@@ -630,22 +651,24 @@ impl<G: Group, K: KemCoreWrapper> Serialize for KemKe1Message<G, K>
where where
Ke1Message<G>: Serialize, Ke1Message<G>: Serialize,
<Ke1Message<G> as Serialize>::Len: Add<K::EncapsulationKeyLen>, <Ke1Message<G> as Serialize>::Len: Add<K::EncapsulationKeyLen>,
Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength<u8>, Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength,
{ {
type Len = Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>; type Len = Sum<<Ke1Message<G> as Serialize>::Len, K::EncapsulationKeyLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_message self.dh_message
.serialize() .serialize()
.concat(self.kem_encapsulation_key.clone()) .cat(self.kem_encapsulation_key.clone())
} }
} }
impl<K: KemCoreWrapper, H: Hash> Deserialize for KemKe2State<K, H> impl<K: KemCoreWrapper, H: Hash> Deserialize for KemKe2State<K, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
@@ -659,16 +682,18 @@ where
impl<K: KemCoreWrapper, H: Hash> Serialize for KemKe2State<K, H> impl<K: KemCoreWrapper, H: Hash> Serialize for KemKe2State<K, H>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
super::tripledh::Ke2State<H>: Serialize, super::tripledh::Ke2State<H>: Serialize,
<super::tripledh::Ke2State<H> as Serialize>::Len: Add<K::EncapsulationKeyLen>, <super::tripledh::Ke2State<H> as Serialize>::Len: Add<K::EncapsulationKeyLen>,
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>: Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>:
ArrayLength<u8> + Add<K::CiphertextLen>, ArrayLength + Add<K::CiphertextLen>,
Sum< Sum<
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>, Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
K::CiphertextLen, K::CiphertextLen,
>: ArrayLength<u8>, >: ArrayLength,
{ {
type Len = Sum< type Len = Sum<
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>, Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
@@ -678,16 +703,18 @@ where
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.base_state self.base_state
.serialize() .serialize()
.concat(self.kem_encapsulation_key.clone()) .cat(self.kem_encapsulation_key.clone())
.concat(self.server_kem_ciphertext.clone()) .cat(self.server_kem_ciphertext.clone())
} }
} }
impl<G: Group, H: Hash, K: KemCoreWrapper> Deserialize for KemKe2Message<G, H, K> impl<G: Group, H: Hash, K: KemCoreWrapper> Deserialize for KemKe2Message<G, H, K>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
{ {
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
@@ -700,21 +727,21 @@ where
impl<G: Group, H: Hash, K: KemCoreWrapper> Serialize for KemKe2Message<G, H, K> impl<G: Group, H: Hash, K: KemCoreWrapper> Serialize for KemKe2Message<G, H, K>
where where
H::Core: ProxyHash, H::Core: ProxyHash,
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>, <<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero, Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
OutputSize<H>: ArrayLength,
NonceLen: Add<G::PkLen>, NonceLen: Add<G::PkLen>,
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>, Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>, Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
super::tripledh::Ke2Message<G, H>: Serialize, super::tripledh::Ke2Message<G, H>: Serialize,
<super::tripledh::Ke2Message<G, H> as Serialize>::Len: Add<K::CiphertextLen>, <super::tripledh::Ke2Message<G, H> as Serialize>::Len: Add<K::CiphertextLen>,
<<super::tripledh::Ke2Message<G, H> as Serialize>::Len as Add<K::CiphertextLen>>::Output: <<super::tripledh::Ke2Message<G, H> as Serialize>::Len as Add<K::CiphertextLen>>::Output:
ArrayLength<u8>, ArrayLength,
{ {
type Len = Sum<<super::tripledh::Ke2Message<G, H> as Serialize>::Len, K::CiphertextLen>; type Len = Sum<<super::tripledh::Ke2Message<G, H> as Serialize>::Len, K::CiphertextLen>;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.dh_message self.dh_message.serialize().cat(self.kem_ciphertext.clone())
.serialize()
.concat(self.kem_ciphertext.clone())
} }
} }
+43 -35
View File
@@ -13,7 +13,7 @@
use derive_where::derive_where; use derive_where::derive_where;
use digest::{Output, OutputSizeUser}; use digest::{Output, OutputSizeUser};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, Rng};
use crate::ciphersuite::CipherSuite; use crate::ciphersuite::CipherSuite;
use crate::errors::ProtocolError; use crate::errors::ProtocolError;
@@ -32,11 +32,7 @@ use crate::serialization::SliceExt;
)) ))
)] )]
#[derive_where(Clone)] #[derive_where(Clone)]
#[derive_where(Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk, SK)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk, SK)]
// `NonZeroScalar` doesn't implement `Debug`.
// TODO: remove after `elliptic-curve` bump to v0.14.
#[cfg_attr(not(test), derive_where(Debug; G::Pk, SK))]
#[cfg_attr(test, derive_where(Debug), derive_where(skip_inner(Debug)))]
pub struct KeyPair<G: Group, SK: Clone = PrivateKey<G>> { pub struct KeyPair<G: Group, SK: Clone = PrivateKey<G>> {
pk: PublicKey<G>, pk: PublicKey<G>,
sk: SK, sk: SK,
@@ -60,7 +56,7 @@ impl<G: Group, SK: Clone> KeyPair<G, SK> {
} }
impl<G: Group> KeyPair<G> { impl<G: Group> KeyPair<G> {
pub(crate) fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self { pub(crate) fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let sk = G::random_sk(rng); let sk = G::random_sk(rng);
let pk = G::public_key(&sk); let pk = G::public_key(&sk);
Self { Self {
@@ -70,7 +66,7 @@ impl<G: Group> KeyPair<G> {
} }
/// Generating a random key pair given a cryptographic rng /// Generating a random key pair given a cryptographic rng
pub(crate) fn derive_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self { pub(crate) fn derive_random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
let mut scalar_bytes = GenericArray::<_, <G as Group>::SkLen>::default(); let mut scalar_bytes = GenericArray::<_, <G as Group>::SkLen>::default();
rng.fill_bytes(&mut scalar_bytes); rng.fill_bytes(&mut scalar_bytes);
let sk = G::derive_scalar(scalar_bytes).unwrap(); let sk = G::derive_scalar(scalar_bytes).unwrap();
@@ -133,7 +129,7 @@ where
impl<G: Group> PrivateKey<G> { impl<G: Group> PrivateKey<G> {
/// Private-key signing implementation /// Private-key signing implementation
pub(crate) fn sign< pub(crate) fn sign<
R: CryptoRng + RngCore, R: CryptoRng + Rng,
CS: CipherSuite, CS: CipherSuite,
SIG: SignatureProtocol<Group = G>, SIG: SignatureProtocol<Group = G>,
KE: Group, KE: Group,
@@ -152,7 +148,7 @@ pub trait PrivateKeySerialization<G: Group>: Clone {
/// Custom error type that can be passed down to `ProtocolError::Custom` /// Custom error type that can be passed down to `ProtocolError::Custom`
type Error; type Error;
/// Serialization size in bytes. /// Serialization size in bytes.
type Len: ArrayLength<u8>; type Len: ArrayLength;
/// Serialization into bytes /// Serialization into bytes
fn serialize_key_pair(key_pair: &KeyPair<G, Self>) -> GenericArray<u8, Self::Len>; fn serialize_key_pair(key_pair: &KeyPair<G, Self>) -> GenericArray<u8, Self::Len>;
@@ -242,7 +238,7 @@ pub struct OprfSeed<H: OutputSizeUser>(pub(crate) Output<H>);
/// Will be called with `E` being [`PrivateKeySerialization::Error`]. /// Will be called with `E` being [`PrivateKeySerialization::Error`].
pub trait OprfSeedSerialization<H, E>: Sized { pub trait OprfSeedSerialization<H, E>: Sized {
/// Serialization size in bytes. /// Serialization size in bytes.
type Len: ArrayLength<u8>; type Len: ArrayLength;
/// Serialization into bytes /// Serialization into bytes
fn serialize(&self) -> GenericArray<u8, Self::Len>; fn serialize(&self) -> GenericArray<u8, Self::Len>;
@@ -253,18 +249,22 @@ pub trait OprfSeedSerialization<H, E>: Sized {
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError<E>>; fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError<E>>;
} }
impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H> { impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H>
where
H::OutputSize: ArrayLength,
{
type Len = H::OutputSize; type Len = H::OutputSize;
fn serialize(&self) -> GenericArray<u8, Self::Len> { fn serialize(&self) -> GenericArray<u8, Self::Len> {
self.0.clone() GenericArray::from_slice(self.0.as_slice()).clone()
} }
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError<E>> { fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError<E>> {
Ok(Self( Ok(Self(
input input
.take_array("OPRF seed") .take_array("OPRF seed")
.map_err(ProtocolError::into_custom)?, .map_err(ProtocolError::into_custom)?
.into_ha0_4(),
)) ))
} }
} }
@@ -275,7 +275,11 @@ impl<H: OutputSizeUser, E> OprfSeedSerialization<H, E> for OprfSeed<H> {
////////////////////////// //////////////////////////
#[cfg(test)] #[cfg(test)]
impl<G: Group> KeyPair<G> { impl<G: Group> KeyPair<G>
where
G::Pk: core::fmt::Debug,
G::Sk: core::fmt::Debug,
{
/// Test-only strategy returning a proptest Strategy based on /// Test-only strategy returning a proptest Strategy based on
/// [`Self::derive_random`] /// [`Self::derive_random`]
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> { fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
@@ -297,9 +301,6 @@ impl<G: Group> KeyPair<G> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hkdf::Hkdf;
use rand::rngs::OsRng;
use super::*; use super::*;
use crate::ciphersuite::{KeGroup, OprfHash}; use crate::ciphersuite::{KeGroup, OprfHash};
use crate::{ use crate::{
@@ -309,6 +310,9 @@ mod tests {
ServerLoginParameters, ServerLoginStartResult, ServerRegistration, ServerLoginParameters, ServerLoginStartResult, ServerRegistration,
ServerRegistrationStartResult, ServerSetup, ServerRegistrationStartResult, ServerSetup,
}; };
use hkdf::Hkdf;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
macro_rules! test { macro_rules! test {
($mod:ident, $point:ty) => { ($mod:ident, $point:ty) => {
@@ -323,7 +327,7 @@ mod tests {
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();
let sk = kp.private(); let sk = kp.private();
prop_assert_eq!(&sk.public_key(), pk); prop_assert_eq!(sk.public_key().serialize(), pk.serialize());
} }
#[test] #[test]
@@ -380,23 +384,24 @@ mod tests {
#[test] #[test]
fn remote_key() { fn remote_key() {
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut OsRng)); let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut UnwrapErr(SysRng)));
let pk = sk.public_key(); let pk = sk.public_key();
let sk = RemoteKey(sk); let sk = RemoteKey(sk);
let keypair = KeyPair::new(sk, pk); let keypair = KeyPair::new(sk, pk);
let server_setup = let server_setup =
ServerSetup::<Default, RemoteKey>::new_with_key_pair(&mut OsRng, keypair); ServerSetup::<Default, RemoteKey>::new_with_key_pair(&mut UnwrapErr(SysRng), keypair);
let ClientRegistrationStartResult { let ClientRegistrationStartResult {
message, message,
state: client, state: client,
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); } = ClientRegistration::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes())
.unwrap();
let ServerRegistrationStartResult { message, .. } = let ServerRegistrationStartResult { message, .. } =
ServerRegistration::start(&server_setup, message, &[]).unwrap(); ServerRegistration::start(&server_setup, message, &[]).unwrap();
let ClientRegistrationFinishResult { message, .. } = client let ClientRegistrationFinishResult { message, .. } = client
.finish( .finish(
&mut OsRng, &mut UnwrapErr(SysRng),
PASSWORD.as_bytes(), PASSWORD.as_bytes(),
message, message,
ClientRegistrationFinishParameters::default(), ClientRegistrationFinishParameters::default(),
@@ -407,9 +412,9 @@ mod tests {
let ClientLoginStartResult { let ClientLoginStartResult {
message, message,
state: client, state: client,
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); } = ClientLogin::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()).unwrap();
let builder = ServerLogin::builder( let builder = ServerLogin::builder(
&mut OsRng, &mut UnwrapErr(SysRng),
&server_setup, &server_setup,
Some(file), Some(file),
message, message,
@@ -425,7 +430,7 @@ mod tests {
} = builder.build(shared_secret).unwrap(); } = builder.build(shared_secret).unwrap();
let ClientLoginFinishResult { message, .. } = client let ClientLoginFinishResult { message, .. } = client
.finish( .finish(
&mut OsRng, &mut UnwrapErr(SysRng),
PASSWORD.as_bytes(), PASSWORD.as_bytes(),
message, message,
ClientLoginFinishParameters::default(), ClientLoginFinishParameters::default(),
@@ -438,22 +443,25 @@ mod tests {
#[test] #[test]
fn remote_seed() { fn remote_seed() {
let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default()); let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default().into_ha0_4());
OsRng.fill_bytes(&mut oprf_seed.0); UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0);
let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut OsRng)); let sk = PrivateKey(KeGroup::<Default>::random_sk(&mut UnwrapErr(SysRng)));
let pk = sk.public_key(); let pk = sk.public_key();
let sk = RemoteKey(sk); let sk = RemoteKey(sk);
let keypair = KeyPair::new(sk, pk); let keypair = KeyPair::new(sk, pk);
let server_setup = ServerSetup::<Default, _, _>::new_with_key_pair_and_seed( let server_setup = ServerSetup::<Default, _, _>::new_with_key_pair_and_seed(
&mut OsRng, keypair, oprf_seed, &mut UnwrapErr(SysRng),
keypair,
oprf_seed,
); );
let ClientRegistrationStartResult { let ClientRegistrationStartResult {
message, message,
state: client, state: client,
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); } = ClientRegistration::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes())
.unwrap();
let km = server_setup.key_material_info(&[]); let km = server_setup.key_material_info(&[]);
let mut ikm = GenericArray::default(); let mut ikm = GenericArray::default();
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0) Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
@@ -464,7 +472,7 @@ mod tests {
ServerRegistration::start_with_key_material(&server_setup, ikm, message).unwrap(); ServerRegistration::start_with_key_material(&server_setup, ikm, message).unwrap();
let ClientRegistrationFinishResult { message, .. } = client let ClientRegistrationFinishResult { message, .. } = client
.finish( .finish(
&mut OsRng, &mut UnwrapErr(SysRng),
PASSWORD.as_bytes(), PASSWORD.as_bytes(),
message, message,
ClientRegistrationFinishParameters::default(), ClientRegistrationFinishParameters::default(),
@@ -475,7 +483,7 @@ mod tests {
let ClientLoginStartResult { let ClientLoginStartResult {
message, message,
state: client, state: client,
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); } = ClientLogin::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()).unwrap();
let km = server_setup.key_material_info(&[]); let km = server_setup.key_material_info(&[]);
let mut ikm = GenericArray::default(); let mut ikm = GenericArray::default();
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0) Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
@@ -483,7 +491,7 @@ mod tests {
.expand_multi_info(&km.info, &mut ikm) .expand_multi_info(&km.info, &mut ikm)
.unwrap(); .unwrap();
let builder = ServerLogin::builder_with_key_material( let builder = ServerLogin::builder_with_key_material(
&mut OsRng, &mut UnwrapErr(SysRng),
&server_setup, &server_setup,
ikm, ikm,
Some(file), Some(file),
@@ -499,7 +507,7 @@ mod tests {
} = builder.build(shared_secret).unwrap(); } = builder.build(shared_secret).unwrap();
let ClientLoginFinishResult { message, .. } = client let ClientLoginFinishResult { message, .. } = client
.finish( .finish(
&mut OsRng, &mut UnwrapErr(SysRng),
PASSWORD.as_bytes(), PASSWORD.as_bytes(),
message, message,
ClientLoginFinishParameters::default(), ClientLoginFinishParameters::default(),
+3 -3
View File
@@ -15,7 +15,7 @@ use crate::errors::InternalError;
/// Used for the key stretching function in OPAQUE /// Used for the key stretching function in OPAQUE
pub trait Ksf: Default { pub trait Ksf: Default {
/// Computes the key stretching function /// Computes the key stretching function
fn hash<L: ArrayLength<u8>>( fn hash<L: ArrayLength>(
&self, &self,
input: GenericArray<u8, L>, input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError>; ) -> Result<GenericArray<u8, L>, InternalError>;
@@ -26,7 +26,7 @@ pub trait Ksf: Default {
pub struct Identity; pub struct Identity;
impl Ksf for Identity { impl Ksf for Identity {
fn hash<L: ArrayLength<u8>>( fn hash<L: ArrayLength>(
&self, &self,
input: GenericArray<u8, L>, input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> { ) -> Result<GenericArray<u8, L>, InternalError> {
@@ -36,7 +36,7 @@ impl Ksf for Identity {
#[cfg(feature = "argon2")] #[cfg(feature = "argon2")]
impl Ksf for argon2::Argon2<'_> { impl Ksf for argon2::Argon2<'_> {
fn hash<L: ArrayLength<u8>>( fn hash<L: ArrayLength>(
&self, &self,
input: GenericArray<u8, L>, input: GenericArray<u8, L>,
) -> Result<GenericArray<u8, L>, InternalError> { ) -> Result<GenericArray<u8, L>, InternalError> {
+242 -221
View File
@@ -27,14 +27,14 @@
//! //!
//! We will use the following choices in this example: //! We will use the following choices in this example:
//! ```ignore //! ```ignore
//! use opaque_ke::CipherSuite; //! use opaque_vx::CipherSuite;
//! //!
//! struct Default; //! struct Default;
//! //!
//! impl CipherSuite for Default { //! impl CipherSuite for Default {
//! type OprfCs = opaque_ke::Ristretto255; //! type OprfCs = opaque_vx::Ristretto255;
//! type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! type Ksf = opaque_ke::ksf::Identity; //! type Ksf = opaque_vx::ksf::Identity;
//! } //! }
//! ``` //! ```
//! See [examples/simple_login.rs](https://github.com/facebook/opaque-ke/blob/main/examples/simple_login.rs) //! See [examples/simple_login.rs](https://github.com/facebook/opaque-ke/blob/main/examples/simple_login.rs)
@@ -50,26 +50,27 @@
//! To set up the protocol, the server begins by creating a `ServerSetup` //! To set up the protocol, the server begins by creating a `ServerSetup`
//! object: //! object:
//! ``` //! ```
//! # use opaque_ke::errors::ProtocolError; //! # use opaque_vx::errors::ProtocolError;
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # use opaque_ke::ServerSetup; //! # use opaque_vx::ServerSetup;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! use rand::RngCore; //! use rand::Rng;
//! use rand::rngs::OsRng; //! use rand::rngs::SysRng;
//! use rand_core::UnwrapErr;
//! //!
//! let mut rng = OsRng; //! let mut rng = UnwrapErr(SysRng);
//! let server_setup = ServerSetup::<Default>::new(&mut rng); //! let server_setup = ServerSetup::<Default>::new(&mut rng);
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
@@ -103,30 +104,31 @@
//! [`ClientRegistration`] which must be persisted on the client for the final //! [`ClientRegistration`] which must be persisted on the client for the final
//! step of client registration. //! step of client registration.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ServerRegistration, //! # ServerRegistration,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! use opaque_ke::ClientRegistration; //! use opaque_vx::ClientRegistration;
//! use rand::RngCore; //! use rand::Rng;
//! use rand::rngs::OsRng; //! use rand::rngs::SysRng;
//! use rand_core::UnwrapErr;
//! //!
//! let mut client_rng = OsRng; //! let mut client_rng = UnwrapErr(SysRng);
//! let client_registration_start_result = //! let client_registration_start_result =
//! ClientRegistration::<Default>::start(&mut client_rng, b"password")?; //! ClientRegistration::<Default>::start(&mut client_rng, b"password")?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
@@ -140,35 +142,36 @@
//! [`ServerRegistrationStartResult`], which consists of a //! [`ServerRegistrationStartResult`], which consists of a
//! [`RegistrationResponse`] to be returned to the client. //! [`RegistrationResponse`] to be returned to the client.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, //! # ClientRegistration,
//! # ServerSetup, //! # ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! use opaque_ke::ServerRegistration; //! use opaque_vx::ServerRegistration;
//! //!
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! let server_registration_start_result = ServerRegistration::<Default>::start( //! let server_registration_start_result = ServerRegistration::<Default>::start(
//! &server_setup, //! &server_setup,
@@ -188,35 +191,36 @@
//! which can be used optionally as described in the [Export Key](#export-key) //! which can be used optionally as described in the [Export Key](#export-key)
//! section. //! section.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerSetup, //! # ClientRegistration, ServerRegistration, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! use opaque_ke::ClientRegistrationFinishParameters; //! use opaque_vx::ClientRegistrationFinishParameters;
//! //!
//! let client_registration_finish_result = client_registration_start_result.state.finish( //! let client_registration_finish_result = client_registration_start_result.state.finish(
//! &mut client_rng, //! &mut client_rng,
@@ -236,32 +240,33 @@
//! [`ServerRegistration::serialize`] to store the password file for use during //! [`ServerRegistration::serialize`] to store the password file for use during
//! the login protocol. //! the login protocol.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -287,29 +292,30 @@
//! [`CredentialRequest`] to be sent to the server, and a [`ClientLogin`] which //! [`CredentialRequest`] to be sent to the server, and a [`ClientLogin`] which
//! must be persisted on the client for the final step of client login. //! must be persisted on the client for the final step of client login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization, //! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! use opaque_ke::ClientLogin; //! # use rand_core::UnwrapErr;
//! use opaque_vx::ClientLogin;
//! //!
//! let mut client_rng = OsRng; //! let mut client_rng = UnwrapErr(SysRng);
//! let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"password")?; //! let client_login_start_result = ClientLogin::<Default>::start(&mut client_rng, b"password")?;
//! # Ok::<(), ProtocolError>(()) //! # Ok::<(), ProtocolError>(())
//! ``` //! ```
@@ -323,32 +329,33 @@
//! a [`ServerLogin`] which must be persisted on the server for the final step //! a [`ServerLogin`] which must be persisted on the server for the final step
//! of login. //! of login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -357,10 +364,10 @@
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! use opaque_ke::{ServerLogin, ServerLoginParameters}; //! use opaque_vx::{ServerLogin, ServerLoginParameters};
//! //!
//! let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?; //! let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
//! let mut server_rng = OsRng; //! let mut server_rng = UnwrapErr(SysRng);
//! let server_login_start_result = ServerLogin::start( //! let server_login_start_result = ServerLogin::start(
//! &mut server_rng, //! &mut server_rng,
//! &server_setup, //! &server_setup,
@@ -393,32 +400,33 @@
//! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key) //! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key)
//! which will match the server's session key upon a successful login. //! which will match the server's session key upon a successful login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -433,7 +441,7 @@
//! # )?; //! # )?;
//! # let server_login_start_result = //! # let server_login_start_result =
//! # ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"[email protected]", ServerLoginParameters::default())?; //! # ServerLogin::start(&mut server_rng, &server_setup, Some(password_file), client_login_start_result.message, b"[email protected]", ServerLoginParameters::default())?;
//! use opaque_ke::ClientLoginFinishParameters; //! use opaque_vx::ClientLoginFinishParameters;
//! //!
//! let client_login_finish_result = client_login_start_result.state.finish( //! let client_login_finish_result = client_login_start_result.state.finish(
//! &mut client_rng, //! &mut client_rng,
@@ -450,32 +458,33 @@
//! to produce an output consisting of the `session_key` sequence of bytes which //! to produce an output consisting of the `session_key` sequence of bytes which
//! will match the client's session key upon a successful login. //! will match the client's session key upon a successful login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
@@ -547,32 +556,33 @@
//! registration (with the `server_s_pk` field of //! registration (with the `server_s_pk` field of
//! [`ClientRegistrationFinishResult`]) matches this field during login. //! [`ClientRegistrationFinishResult`]) matches this field during login.
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! // During registration, the client obtains a ClientRegistrationFinishResult with //! // During registration, the client obtains a ClientRegistrationFinishResult with
@@ -644,32 +654,33 @@
//! You can access the export key from the `export_key` field of //! You can access the export key from the `export_key` field of
//! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`]. //! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`].
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! // During registration... //! // During registration...
@@ -727,20 +738,20 @@
//! the ciphersuite as follows: //! the ciphersuite as follows:
//! //!
//! ```ignore //! ```ignore
//! use opaque_ke::CipherSuite; //! use opaque_vx::CipherSuite;
//! //!
//! struct KemSuite; //! struct KemSuite;
//! //!
//! impl CipherSuite for KemSuite { //! impl CipherSuite for KemSuite {
//! type OprfCs = opaque_ke::Ristretto255; //! type OprfCs = opaque_vx::Ristretto255;
//! type KeyExchange = opaque_ke::TripleDhKem<opaque_ke::Ristretto255, sha2::Sha512, opaque_ke::ml_kem::MlKem768>; //! type KeyExchange = opaque_vx::TripleDhKem<opaque_vx::Ristretto255, sha2::Sha512, opaque_vx::ml_kem::MlKem768>;
//! type Ksf = opaque_ke::ksf::Identity; //! type Ksf = opaque_vx::ksf::Identity;
//! } //! }
//! ``` //! ```
//! //!
//! ## Custom Identifiers //! ## Custom Identifiers
//! //!
//! Typically when applications use OPAQUE to authenticate a client to a server, //! Typically, when applications use OPAQUE to authenticate a client to a server,
//! the client has a registered username which is sent to the server to identify //! the client has a registered username which is sent to the server to identify
//! the corresponding password file established during registration. This //! the corresponding password file established during registration. This
//! username may or may not coincide with the server-side identifier; however, //! username may or may not coincide with the server-side identifier; however,
@@ -756,32 +767,33 @@
//! [`ClientRegistrationFinishParameters`] in [Client Registration //! [`ClientRegistrationFinishParameters`] in [Client Registration
//! Finish](#client-registration-finish): //! Finish](#client-registration-finish):
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! let client_registration_finish_result = client_registration_start_result.state.finish( //! let client_registration_finish_result = client_registration_start_result.state.finish(
@@ -802,32 +814,33 @@
//! The same identifiers must also be supplied using [`ServerLoginParameters`] //! The same identifiers must also be supplied using [`ServerLoginParameters`]
//! in [Server Login Start](#server-login-start): //! in [Server Login Start](#server-login-start):
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -836,9 +849,9 @@
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # use opaque_ke::{ServerLogin, ServerLoginParameters}; //! # use opaque_vx::{ServerLogin, ServerLoginParameters};
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?; //! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! let server_login_start_result = ServerLogin::start( //! let server_login_start_result = ServerLogin::start(
//! &mut server_rng, //! &mut server_rng,
//! &server_setup, //! &server_setup,
@@ -859,32 +872,33 @@
//! as well as [`ClientLoginFinishParameters`] in [Client Login //! as well as [`ClientLoginFinishParameters`] in [Client Login
//! Finish](#client-login-finish): //! Finish](#client-login-finish):
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -918,32 +932,33 @@
//! and in [`ServerLoginParameters`] in [Server Login //! and in [`ServerLoginParameters`] in [Server Login
//! Finish](#server-login-finish): //! Finish](#server-login-finish):
//! ``` //! ```
//! # use opaque_ke::{ //! # use opaque_vx::{
//! # errors::ProtocolError, //! # errors::ProtocolError,
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup, //! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
//! # ksf::Identity, //! # ksf::Identity,
//! # }; //! # };
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # use rand::{rngs::OsRng, RngCore}; //! # use rand::{rngs::SysRng, Rng};
//! # let mut client_rng = OsRng; //! # use rand_core::UnwrapErr;
//! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut client_rng, //! # &mut client_rng,
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<Default>::new(&mut server_rng); //! # let server_setup = ServerSetup::<Default>::new(&mut server_rng);
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut client_rng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::new(Identifiers { client: Some(b"Alice_the_Cryptographer"), server: Some(b"Facebook") }, None))?;
@@ -981,7 +996,7 @@
//! //!
//! A key exchange protocol typically allows for the specifying of shared //! A key exchange protocol typically allows for the specifying of shared
//! "context" information between the two parties before the exchange is //! "context" information between the two parties before the exchange is
//! complete, so as to bind the integrity of application-specific data or //! complete, to bind the integrity of application-specific data or
//! configuration parameters to the security of the key exchange. During the //! configuration parameters to the security of the key exchange. During the
//! login phase, the client and server can specify this context using: //! login phase, the client and server can specify this context using:
//! - In [Server Login Start](#server-login-start), where the server can //! - In [Server Login Start](#server-login-start), where the server can
@@ -1008,21 +1023,23 @@
//! exposing the bytes of the private key to this library. //! exposing the bytes of the private key to this library.
//! ``` //! ```
//! # use generic_array::{GenericArray, typenum::U0}; //! # use generic_array::{GenericArray, typenum::U0};
//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}}; //! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::OsRng; //! # use rand::rngs::SysRng;
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group; //! # use rand_core::UnwrapErr;
//!
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[derive(Debug, thiserror::Error)] //! # #[derive(Debug, thiserror::Error)]
//! # #[error("test error")] //! # #[error("test error")]
@@ -1034,9 +1051,9 @@
//! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type())) //! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
//! # } //! # }
//! # } //! # }
//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerSetup}; //! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerSetup};
//! use opaque_ke::keypair::{KeyPair, PrivateKeySerialization}; //! use opaque_vx::keypair::{KeyPair, PrivateKeySerialization};
//! use opaque_ke::errors::ProtocolError; //! use opaque_vx::errors::ProtocolError;
//! //!
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`. //! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
//! impl PrivateKeySerialization<Ristretto255> for YourRemoteKey { //! impl PrivateKeySerialization<Ristretto255> for YourRemoteKey {
@@ -1052,24 +1069,24 @@
//! } //! }
//! } //! }
//! //!
//! # let sk = Ristretto255::random_sk(&mut OsRng); //! # let sk = Ristretto255::random_sk(&mut UnwrapErr(SysRng));
//! # let pk = Ristretto255::public_key(&sk); //! # let pk = Ristretto255::public_key(&sk);
//! # let pk = Ristretto255::serialize_pk(&pk); //! # let pk = Ristretto255::serialize_pk(&pk);
//! # let public_key = PublicKey::deserialize(&pk).unwrap(); //! # let public_key = PublicKey::deserialize(&pk).unwrap();
//! # let remote_key = YourRemoteKey(sk); //! # let remote_key = YourRemoteKey(sk);
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! let keypair = KeyPair::new(remote_key, public_key); //! let keypair = KeyPair::new(remote_key, public_key);
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key_pair(&mut server_rng, keypair); //! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key_pair(&mut server_rng, keypair);
//! //!
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut OsRng, //! # &mut UnwrapErr(SysRng),
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?; //! # let server_registration_start_result = ServerRegistration::<Default>::start(&server_setup, client_registration_start_result.message, b"[email protected]")?;
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut UnwrapErr(SysRng), b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize(); //! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
//! # let client_login_start_result = ClientLogin::<Default>::start( //! # let client_login_start_result = ClientLogin::<Default>::start(
//! # &mut OsRng, //! # &mut UnwrapErr(SysRng),
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?; //! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
@@ -1102,24 +1119,26 @@
//! # use digest::Output; //! # use digest::Output;
//! # use generic_array::{GenericArray, typenum::U0}; //! # use generic_array::{GenericArray, typenum::U0};
//! # use hkdf::Hkdf; //! # use hkdf::Hkdf;
//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}}; //! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
//! # use rand::rngs::OsRng; //! # use rand::rngs::SysRng;
//! # use rand::RngCore; //! # use rand::Rng;
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group; //! # use rand_core::UnwrapErr;
//!
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
//! # type Hash = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Hash; //! # type Hash = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Hash;
//! # type OprfGroup = <<Default as CipherSuite>::OprfCs as voprf::CipherSuite>::Group; //! # type OprfGroup = <<Default as CipherSuite>::OprfCs as voprf::CipherSuite>::Group;
//! # struct Default; //! # struct Default;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for Default { //! # impl CipherSuite for Default {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = opaque_ke::ksf::Identity; //! # type Ksf = opaque_vx::ksf::Identity;
//! # } //! # }
//! # #[derive(Debug, thiserror::Error)] //! # #[derive(Debug, thiserror::Error)]
//! # #[error("test error")] //! # #[error("test error")]
@@ -1143,9 +1162,9 @@
//! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type())) //! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
//! # } //! # }
//! # } //! # }
//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup}; //! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup};
//! use opaque_ke::keypair::{KeyPair, OprfSeedSerialization}; //! use opaque_vx::keypair::{KeyPair, OprfSeedSerialization};
//! use opaque_ke::errors::ProtocolError; //! use opaque_vx::errors::ProtocolError;
//! //!
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`. //! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
//! impl OprfSeedSerialization<sha2::Sha512, YourRemoteSecretsError> for YourRemoteSeed { //! impl OprfSeedSerialization<sha2::Sha512, YourRemoteSecretsError> for YourRemoteSeed {
@@ -1160,20 +1179,20 @@
//! } //! }
//! } //! }
//! //!
//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default()); //! # let mut oprf_seed = YourRemoteSeed(GenericArray::default().into_ha0_4());
//! # OsRng.fill_bytes(&mut oprf_seed.0); //! # UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0);
//! # let sk = Ristretto255::random_sk(&mut OsRng); //! # let sk = Ristretto255::random_sk(&mut UnwrapErr(SysRng));
//! # let pk = Ristretto255::public_key(&sk); //! # let pk = Ristretto255::public_key(&sk);
//! # let pk = Ristretto255::serialize_pk(&pk); //! # let pk = Ristretto255::serialize_pk(&pk);
//! # let public_key = PublicKey::deserialize(&pk).unwrap(); //! # let public_key = PublicKey::deserialize(&pk).unwrap();
//! # let remote_key = YourRemoteKey(sk); //! # let remote_key = YourRemoteKey(sk);
//! # let mut server_rng = OsRng; //! # let mut server_rng = UnwrapErr(SysRng);
//! let keypair = KeyPair::new(remote_key, public_key); //! let keypair = KeyPair::new(remote_key, public_key);
//! let server_setup = ServerSetup::<Default, YourRemoteKey, YourRemoteSeed>::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed); //! let server_setup = ServerSetup::<Default, YourRemoteKey, YourRemoteSeed>::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed);
//! //!
//! // Incoming registration ... //! // Incoming registration ...
//! # let client_registration_start_result = ClientRegistration::<Default>::start( //! # let client_registration_start_result = ClientRegistration::<Default>::start(
//! # &mut OsRng, //! # &mut UnwrapErr(SysRng),
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! //!
@@ -1189,12 +1208,12 @@
//! )?; //! )?;
//! //!
//! // Finish registration ... //! // Finish registration ...
//! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut OsRng, b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?; //! # let client_registration_finish_result = client_registration_start_result.state.finish(&mut UnwrapErr(SysRng), b"password", server_registration_start_result.message, ClientRegistrationFinishParameters::default())?;
//! //!
//! // Incoming login ... //! // Incoming login ...
//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize(); //! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
//! # let client_login_start_result = ClientLogin::<Default>::start( //! # let client_login_start_result = ClientLogin::<Default>::start(
//! # &mut OsRng, //! # &mut UnwrapErr(SysRng),
//! # b"password", //! # b"password",
//! # )?; //! # )?;
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?; //! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
@@ -1231,20 +1250,20 @@
//! can be used. //! can be used.
//! ``` //! ```
//! # use generic_array::GenericArray; //! # use generic_array::GenericArray;
//! use opaque_ke::ksf::Ksf; //! use opaque_vx::ksf::Ksf;
//! //!
//! #[derive(Default)] //! #[derive(Default)]
//! struct CustomKsf(scrypt::Params); //! struct CustomKsf(scrypt::Params);
//! //!
//! // The Ksf trait must be implemented to be used in the ciphersuite. //! // The Ksf trait must be implemented to be used in the ciphersuite.
//! impl Ksf for CustomKsf { //! impl Ksf for CustomKsf {
//! fn hash<L: generic_array::ArrayLength<u8>>( //! fn hash<L: generic_array::ArrayLength>(
//! &self, //! &self,
//! input: GenericArray<u8, L>, //! input: GenericArray<u8, L>,
//! ) -> Result<GenericArray<u8, L>, opaque_ke::errors::InternalError> { //! ) -> Result<GenericArray<u8, L>, opaque_vx::errors::InternalError> {
//! let mut output = GenericArray::<u8, L>::default(); //! let mut output = GenericArray::<u8, L>::default();
//! scrypt::scrypt(&input, &[], &self.0, &mut output) //! scrypt::scrypt(&input, &[], &self.0, &mut output)
//! .map_err(|_| opaque_ke::errors::InternalError::KsfError)?; //! .map_err(|_| opaque_vx::errors::InternalError::KsfError)?;
//! //!
//! Ok(output) //! Ok(output)
//! } //! }
@@ -1255,37 +1274,38 @@
//! used by the KSF during registration and login. This can be especially //! used by the KSF during registration and login. This can be especially
//! helpful if the `Ksf` trait is already implemented. //! helpful if the `Ksf` trait is already implemented.
//! ``` //! ```
//! # use opaque_ke::CipherSuite; //! # use opaque_vx::CipherSuite;
//! # use opaque_ke::ClientRegistration; //! # use opaque_vx::ClientRegistration;
//! # use opaque_ke::ClientRegistrationFinishParameters; //! # use opaque_vx::ClientRegistrationFinishParameters;
//! # use opaque_ke::ServerSetup; //! # use opaque_vx::ServerSetup;
//! # use opaque_ke::errors::ProtocolError; //! # use opaque_vx::errors::ProtocolError;
//! # use rand::rngs::OsRng; //! # use rand::rngs::SysRng;
//! # use rand::RngCore; //! # use rand::Rng;
//! # use rand_core::UnwrapErr;
//! # use std::default::Default; //! # use std::default::Default;
//! # #[cfg(feature = "argon2")] //! # #[cfg(feature = "argon2")]
//! # { //! # {
//! # struct DefaultCipherSuite; //! # struct DefaultCipherSuite;
//! # #[cfg(feature = "ristretto255")] //! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for DefaultCipherSuite { //! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = opaque_ke::Ristretto255; //! # type OprfCs = opaque_vx::Ristretto255;
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>; //! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
//! # type Ksf = argon2::Argon2<'static>; //! # type Ksf = argon2::Argon2<'static>;
//! # } //! # }
//! # #[cfg(not(feature = "ristretto255"))] //! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for DefaultCipherSuite { //! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = p256::NistP256; //! # type OprfCs = p256::NistP256;
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>; //! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
//! # type Ksf = argon2::Argon2<'static>; //! # type Ksf = argon2::Argon2<'static>;
//! # } //! # }
//! # //! #
//! # let password = b"password"; //! # let password = b"password";
//! # let mut rng = OsRng; //! # let mut rng = UnwrapErr(SysRng);
//! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng); //! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
//! # let mut client_rng = OsRng; //! # let mut client_rng = UnwrapErr(SysRng);
//! # let client_registration_start_result = //! # let client_registration_start_result =
//! # ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?; //! # ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?;
//! # use opaque_ke::ServerRegistration; //! # use opaque_vx::ServerRegistration;
//! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start( //! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
//! # &server_setup, //! # &server_setup,
//! # client_registration_start_result.message, //! # client_registration_start_result.message,
@@ -1384,6 +1404,7 @@ mod tests;
#[cfg(feature = "argon2")] #[cfg(feature = "argon2")]
pub use argon2; pub use argon2;
pub use generic_array; pub use generic_array;
pub use hybrid_array;
#[cfg(feature = "kem")] #[cfg(feature = "kem")]
pub use ml_kem; pub use ml_kem;
pub use rand; pub use rand;
+57 -39
View File
@@ -15,7 +15,8 @@ use digest::Output;
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, Unsigned}; use generic_array::typenum::{Sum, Unsigned};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand::{CryptoRng, RngCore}; use hybrid_array::Array;
use rand::{CryptoRng, Rng};
use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen}; use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -50,7 +51,7 @@ use crate::serialization::SliceExt;
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)]
pub struct RegistrationRequest<CS: CipherSuite> { pub struct RegistrationRequest<CS: CipherSuite> {
/// blinded password information /// blinded password information
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>, pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
} }
/// The answer sent by the server to the user, upon reception of the /// The answer sent by the server to the user, upon reception of the
@@ -64,10 +65,11 @@ pub struct RegistrationRequest<CS: CipherSuite> {
)) ))
)] )]
#[derive_where(Clone)] #[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <KeGroup<CS> as Group>::Pk)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement<CS::OprfCs>, <KeGroup<CS> as Group>::Pk
)]
pub struct RegistrationResponse<CS: CipherSuite> { pub struct RegistrationResponse<CS: CipherSuite> {
/// The server's oprf output /// The server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>, pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
/// Server's static public key /// Server's static public key
pub(crate) server_s_pk: PublicKey<KeGroup<CS>>, pub(crate) server_s_pk: PublicKey<KeGroup<CS>>,
} }
@@ -111,7 +113,7 @@ pub struct RegistrationUpload<CS: CipherSuite> {
<CS::KeyExchange as KeyExchange>::KE1Message, <CS::KeyExchange as KeyExchange>::KE1Message,
)] )]
pub struct CredentialRequest<CS: CipherSuite> { pub struct CredentialRequest<CS: CipherSuite> {
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>, pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
pub(crate) ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message, pub(crate) ke1_message: <CS::KeyExchange as KeyExchange>::KE1Message,
} }
@@ -136,7 +138,7 @@ pub struct CredentialRequest<CS: CipherSuite> {
)] )]
pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> { pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> {
pub(crate) server_s_sk: SK, pub(crate) server_s_sk: SK,
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>, pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>, pub(crate) masking_nonce: Zeroizing<GenericArray<u8, NonceLen>>,
pub(crate) masked_response: MaskedResponse<CS>, pub(crate) masked_response: MaskedResponse<CS>,
#[cfg(test)] #[cfg(test)]
@@ -184,12 +186,12 @@ impl<CS: CipherSuite, SK: Clone> ServerLoginBuilder<'_, CS, SK> {
#[derive_where(Clone)] #[derive_where(Clone)]
#[derive_where( #[derive_where(
Debug, Eq, Hash, PartialEq; Debug, Eq, Hash, PartialEq;
voprf::EvaluationElement<CS::OprfCs>, EvaluationElement<CS::OprfCs>,
<CS::KeyExchange as KeyExchange>::KE2Message, <CS::KeyExchange as KeyExchange>::KE2Message,
)] )]
pub struct CredentialResponse<CS: CipherSuite> { pub struct CredentialResponse<CS: CipherSuite> {
/// the server's oprf output /// the server's oprf output
pub(crate) evaluation_element: voprf::EvaluationElement<CS::OprfCs>, pub(crate) evaluation_element: EvaluationElement<CS::OprfCs>,
pub(crate) masking_nonce: GenericArray<u8, NonceLen>, pub(crate) 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>::KE2Message, pub(crate) ke2_message: <CS::KeyExchange as KeyExchange>::KE2Message,
@@ -225,19 +227,19 @@ pub type RegistrationRequestLen<CS: CipherSuite> = <OprfGroup<CS> as voprf::Grou
impl<CS: CipherSuite> RegistrationRequest<CS> { impl<CS: CipherSuite> RegistrationRequest<CS> {
/// Only used for testing purposes /// Only used for testing purposes
#[cfg(test)] #[cfg(test)]
pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> { pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
self.blinded_element.clone() self.blinded_element.clone()
} }
/// Serialization into bytes /// Serialization into bytes
pub fn serialize(&self) -> GenericArray<u8, RegistrationRequestLen<CS>> { pub fn serialize(&self) -> Array<u8, RegistrationRequestLen<CS>> {
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value()) <OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value())
} }
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
blinded_element: voprf::BlindedElement::deserialize(input)?, blinded_element: BlindedElement::deserialize(input)?,
}) })
} }
} }
@@ -251,11 +253,14 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>> pub fn serialize(&self) -> GenericArray<u8, RegistrationResponseLen<CS>>
where where
// RegistrationResponse: KgPk + KePk // RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen> + ArrayLength,
RegistrationResponseLen<CS>: ArrayLength<u8>, RegistrationResponseLen<CS>: ArrayLength,
{ {
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value()) let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
.concat(self.server_s_pk.serialize()) self.evaluation_element.value(),
));
elem.concat(self.server_s_pk.serialize())
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -277,7 +282,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
beta: <OprfGroup<CS> as voprf::Group>::Elem, beta: <OprfGroup<CS> as voprf::Group>::Elem,
) -> Self { ) -> Self {
Self { Self {
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), evaluation_element: EvaluationElement::from_value_unchecked(beta),
server_s_pk: self.server_s_pk.clone(), server_s_pk: self.server_s_pk.clone(),
} }
} }
@@ -294,26 +299,29 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
{ {
self.client_s_pk Concat::concat(
.serialize() Concat::concat(
.concat(self.masking_key.clone()) self.client_s_pk.serialize(),
.concat(self.envelope.serialize()) GenericArray::from_slice(self.masking_key.as_slice()).clone(),
),
self.envelope.serialize(),
)
} }
/// Deserialization from bytes /// Deserialization from bytes
pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> { pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
client_s_pk: PublicKey::deserialize_take(&mut input)?, client_s_pk: PublicKey::deserialize_take(&mut input)?,
masking_key: input.take_array("masking key")?, masking_key: input.take_array("masking key")?.into_ha0_4(),
envelope: Envelope::deserialize_take(&mut input)?, envelope: Envelope::deserialize_take(&mut input)?,
}) })
} }
// Creates a dummy instance used for faking a [CredentialResponse] // Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, OS: Clone>( pub(crate) fn dummy<R: Rng + CryptoRng, SK: Clone, OS: Clone>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, SK, OS>, server_setup: &ServerSetup<CS, SK, OS>,
) -> Self { ) -> Self {
@@ -338,11 +346,14 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
where where
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>> + ArrayLength,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
{ {
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value()) let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
.concat(self.ke1_message.serialize()) self.blinded_element.value(),
));
elem.concat(self.ke1_message.serialize())
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -372,7 +383,7 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
/// Only used for testing purposes /// Only used for testing purposes
#[cfg(test)] #[cfg(test)]
pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement<CS::OprfCs> { pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement<CS::OprfCs> {
self.blinded_element.clone() self.blinded_element.clone()
} }
} }
@@ -390,18 +401,25 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
where where
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen> + ArrayLength,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value()) let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
.concat(self.masking_nonce) self.evaluation_element.value(),
.concat(self.masked_response.serialize()) ));
.concat(self.ke2_message.serialize())
Concat::concat(
Concat::concat(
Concat::concat(elem, self.masking_nonce),
self.masked_response.serialize(),
),
self.ke2_message.serialize(),
)
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -410,7 +428,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize, <CS::KeyExchange as KeyExchange>::KE2Message: Deserialize,
{ {
let evaluation_element = EvaluationElement::deserialize(input)?; let evaluation_element = EvaluationElement::deserialize(input)?;
input = &input[voprf::EvaluationElementLen::<CS::OprfCs>::USIZE..]; input = &input[EvaluationElementLen::<CS::OprfCs>::USIZE..];
Ok(Self { Ok(Self {
evaluation_element, evaluation_element,
@@ -438,7 +456,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
beta: <OprfGroup<CS> as voprf::Group>::Elem, beta: <OprfGroup<CS> as voprf::Group>::Elem,
) -> Self { ) -> Self {
Self { Self {
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta), evaluation_element: EvaluationElement::from_value_unchecked(beta),
masking_nonce: self.masking_nonce, masking_nonce: self.masking_nonce,
masked_response: self.masked_response.clone(), masked_response: self.masked_response.clone(),
ke2_message: self.ke2_message.clone(), ke2_message: self.ke2_message.clone(),
+74 -66
View File
@@ -8,15 +8,14 @@
//! Provides the main OPAQUE API //! Provides the main OPAQUE API
use core::ops::{Add, Deref}; use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::Output; use digest::Output;
use generic_array::sequence::Concat;
use generic_array::typenum::{Sum, Unsigned}; use generic_array::typenum::{Sum, Unsigned};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hkdf::{Hkdf, HkdfExtract}; use hkdf::Hkdf;
use rand::{CryptoRng, RngCore}; use hkdf::SimpleHkdfExtract as HkdfExtract;
use rand::{CryptoRng, Rng};
use subtle::{Choice, ConstantTimeEq, CtOption}; use subtle::{Choice, ConstantTimeEq, CtOption};
use voprf::{BlindedElement, Group as _, OprfClient, OprfClientLen}; use voprf::{BlindedElement, Group as _, OprfClient, OprfClientLen};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -36,7 +35,7 @@ use crate::keypair::{
}; };
use crate::ksf::Ksf; use crate::ksf::Ksf;
use crate::messages::{CredentialRequestLen, RegistrationUploadLen}; use crate::messages::{CredentialRequestLen, RegistrationUploadLen};
use crate::serialization::{GenericArrayExt, SliceExt}; use crate::serialization::{ConcatExt, GenericArrayExt, SliceExt};
use crate::{ use crate::{
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest, CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
RegistrationResponse, RegistrationUpload, ServerLoginBuilder, RegistrationResponse, RegistrationUpload, ServerLoginBuilder,
@@ -70,7 +69,8 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
)) ))
)] )]
#[derive_where(Clone)] #[derive_where(Clone)]
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <KeGroup<CS> as Group>::Pk, <KeGroup<CS> as Group>::Sk, SK, OS)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; <KeGroup<CS> as Group>::Pk, <KeGroup<CS> as Group>::Sk, SK, OS
)]
pub struct ServerSetup< pub struct ServerSetup<
CS: CipherSuite, CS: CipherSuite,
SK: Clone = PrivateKey<KeGroup<CS>>, SK: Clone = PrivateKey<KeGroup<CS>>,
@@ -94,8 +94,8 @@ pub struct ServerSetup<
voprf::BlindedElement<CS::OprfCs>, voprf::BlindedElement<CS::OprfCs>,
)] )]
pub struct ClientRegistration<CS: CipherSuite> { pub struct ClientRegistration<CS: CipherSuite> {
pub(crate) oprf_client: voprf::OprfClient<CS::OprfCs>, pub(crate) oprf_client: OprfClient<CS::OprfCs>,
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>, pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
} }
/// The state elements the server holds to record a registration /// The state elements the server holds to record a registration
@@ -130,7 +130,7 @@ pub struct ServerRegistration<CS: CipherSuite>(pub(crate) RegistrationUpload<CS>
CredentialRequest<CS>, CredentialRequest<CS>,
)] )]
pub struct ClientLogin<CS: CipherSuite> { pub struct ClientLogin<CS: CipherSuite> {
pub(crate) oprf_client: voprf::OprfClient<CS::OprfCs>, pub(crate) oprf_client: OprfClient<CS::OprfCs>,
pub(crate) ke1_state: <CS::KeyExchange as KeyExchange>::KE1State, pub(crate) ke1_state: <CS::KeyExchange as KeyExchange>::KE1State,
pub(crate) credential_request: CredentialRequest<CS>, pub(crate) credential_request: CredentialRequest<CS>,
} }
@@ -160,7 +160,7 @@ pub struct ServerLogin<CS: CipherSuite> {
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<KeGroup<CS>>> { impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<KeGroup<CS>>> {
/// Generate a new instance of server setup /// Generate a new instance of server setup
pub fn new<R: CryptoRng + RngCore>(rng: &mut R) -> Self { pub fn new<R: CryptoRng + Rng>(rng: &mut R) -> Self {
let keypair = KeyPair::random(rng); let keypair = KeyPair::random(rng);
Self::new_with_key_pair(rng, keypair) Self::new_with_key_pair(rng, keypair)
} }
@@ -179,7 +179,7 @@ impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
/// This function should not be used to restore a previously-existing /// This function should not be used to restore a previously-existing
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and /// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
/// [`ServerSetup::deserialize`] for this purpose. /// [`ServerSetup::deserialize`] for this purpose.
pub fn new_with_key_pair_and_seed<R: CryptoRng + RngCore>( pub fn new_with_key_pair_and_seed<R: CryptoRng + Rng>(
rng: &mut R, rng: &mut R,
keypair: KeyPair<KeGroup<CS>, SK>, keypair: KeyPair<KeGroup<CS>, SK>,
oprf_seed: OS, oprf_seed: OS,
@@ -211,13 +211,13 @@ impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>, OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
// ServerSetup: Hash + KeSk + KePk // ServerSetup: Hash + KeSk + KePk
OS::Len: Add<SK::Len>, OS::Len: Add<SK::Len>,
Sum<OS::Len, SK::Len>: ArrayLength<u8> + Add<<KeGroup<CS> as Group>::PkLen>, Sum<OS::Len, SK::Len>: ArrayLength + Add<<KeGroup<CS> as Group>::PkLen>,
ServerSetupLen<CS, SK, OS>: ArrayLength<u8>, ServerSetupLen<CS, SK, OS>: ArrayLength,
{ {
self.oprf_seed self.oprf_seed
.serialize() .serialize()
.concat(SK::serialize_key_pair(&self.keypair)) .cat(SK::serialize_key_pair(&self.keypair))
.concat(self.dummy_pk.serialize()) .cat(self.dummy_pk.serialize())
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -246,11 +246,11 @@ impl<CS: CipherSuite, SK: Clone> ServerSetup<CS, SK> {
/// This function should not be used to restore a previously-existing /// This function should not be used to restore a previously-existing
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and /// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
/// [`ServerSetup::deserialize`] for this purpose. /// [`ServerSetup::deserialize`] for this purpose.
pub fn new_with_key_pair<R: CryptoRng + RngCore>( pub fn new_with_key_pair<R: CryptoRng + Rng>(
rng: &mut R, rng: &mut R,
keypair: KeyPair<KeGroup<CS>, SK>, keypair: KeyPair<KeGroup<CS>, SK>,
) -> Self { ) -> Self {
let mut oprf_seed = GenericArray::default(); let mut oprf_seed = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut oprf_seed); rng.fill_bytes(&mut oprf_seed);
Self::new_with_key_pair_and_seed(rng, keypair, OprfSeed(oprf_seed)) Self::new_with_key_pair_and_seed(rng, keypair, OprfSeed(oprf_seed))
@@ -282,12 +282,13 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
pub fn serialize(&self) -> GenericArray<u8, ClientRegistrationLen<CS>> pub fn serialize(&self) -> GenericArray<u8, ClientRegistrationLen<CS>>
where where
// ClientRegistration: KgSk + KgPk // ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>, <OprfGroup<CS> as voprf::Group>::ScalarLen:
ClientRegistrationLen<CS>: ArrayLength<u8>, Add<<OprfGroup<CS> as voprf::Group>::ElemLen> + ArrayLength,
<OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
ClientRegistrationLen<CS>: ArrayLength,
{ {
self.oprf_client GenericArray::from_ha0_4(self.oprf_client.serialize())
.serialize() .cat(GenericArray::from_ha0_4(self.blinded_element.serialize()))
.concat(self.blinded_element.serialize())
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -305,7 +306,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// Returns an initial "blinded" request to send to the server, as well as a /// Returns an initial "blinded" request to send to the server, as well as a
/// [`ClientRegistration`] /// [`ClientRegistration`]
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: Rng + CryptoRng>(
blinding_factor_rng: &mut R, blinding_factor_rng: &mut R,
password: &[u8], password: &[u8],
) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> { ) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> {
@@ -325,7 +326,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
/// "Unblinds" the server's answer and returns a final message containing /// "Unblinds" the server's answer and returns a final message containing
/// cryptographic identifiers, to be sent to the server on setup /// cryptographic identifiers, to be sent to the server on setup
/// finalization /// finalization
pub fn finish<R: CryptoRng + RngCore>( pub fn finish<R: CryptoRng + Rng>(
self, self,
rng: &mut R, rng: &mut R,
password: &[u8], password: &[u8],
@@ -357,7 +358,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
let result = Envelope::<CS>::seal( let result = Envelope::<CS>::seal(
rng, rng,
randomized_pwd_hasher, &randomized_pwd_hasher,
&registration_response.server_s_pk, &registration_response.server_s_pk,
params.identifiers, params.identifiers,
)?; )?;
@@ -390,8 +391,8 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
{ {
self.0.serialize() self.0.serialize()
@@ -449,7 +450,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
} }
// Creates a dummy instance used for faking a [CredentialResponse] // Creates a dummy instance used for faking a [CredentialResponse]
pub(crate) fn dummy<R: RngCore + CryptoRng, SK: Clone, S: Clone>( pub(crate) fn dummy<R: Rng + CryptoRng, SK: Clone, S: Clone>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, SK, S>, server_setup: &ServerSetup<CS, SK, S>,
) -> Self { ) -> Self {
@@ -470,18 +471,17 @@ impl<CS: CipherSuite> ClientLogin<CS> {
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State // ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize, <CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>: Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>, ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>, ClientLoginLen<CS>: ArrayLength,
{ {
self.oprf_client GenericArray::from_ha0_4(self.oprf_client.serialize())
.serialize() .cat(self.credential_request.serialize())
.concat(self.credential_request.serialize()) .cat(self.ke1_state.serialize())
.concat(self.ke1_state.serialize())
} }
/// Deserialization from bytes /// Deserialization from bytes
@@ -504,7 +504,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
impl<CS: CipherSuite> ClientLogin<CS> { impl<CS: CipherSuite> ClientLogin<CS> {
/// Returns an initial "blinded" password request to send to the server, as /// Returns an initial "blinded" password request to send to the server, as
/// well as a [`ClientLogin`] /// well as a [`ClientLogin`]
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
password: &[u8], password: &[u8],
) -> Result<ClientLoginStartResult<CS>, ProtocolError> { ) -> Result<ClientLoginStartResult<CS>, ProtocolError> {
@@ -528,7 +528,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
/// "Unblinds" the server's answer and returns the opened assets from the /// "Unblinds" the server's answer and returns the opened assets from the
/// server /// server
pub fn finish<R: CryptoRng + RngCore>( pub fn finish<R: CryptoRng + Rng>(
self, self,
rng: &mut R, rng: &mut R,
password: &[u8], password: &[u8],
@@ -570,7 +570,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
let opened_envelope = envelope let opened_envelope = envelope
.open( .open(
randomized_pwd_hasher, &randomized_pwd_hasher,
server_s_pk.clone(), server_s_pk.clone(),
params.identifiers, params.identifiers,
) )
@@ -641,7 +641,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// ///
/// See [`ServerLogin::start()`] for the regular path. Or /// See [`ServerLogin::start()`] for the regular path. Or
/// [`ServerLogin::builder()`] with just a remote private key. /// [`ServerLogin::builder()`] with just a remote private key.
pub fn builder_with_key_material<'a, R: RngCore + CryptoRng, SK: Clone, OS: Clone>( pub fn builder_with_key_material<'a, R: Rng + CryptoRng, SK: Clone, OS: Clone>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, SK, OS>, server_setup: &ServerSetup<CS, SK, OS>,
key_material: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, key_material: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
@@ -668,7 +668,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let masked_response = mask_response( let masked_response = mask_response(
&record.0.masking_key, &record.0.masking_key,
masking_nonce.as_slice(), &masking_nonce,
server_s_pk, server_s_pk,
&record.0.envelope, &record.0.envelope,
)?; )?;
@@ -715,7 +715,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
/// Create a [`ServerLoginBuilder`] to use with a remote private key. /// Create a [`ServerLoginBuilder`] to use with a remote private key.
/// ///
/// See [`ServerLogin::start()`] for the regular path. /// See [`ServerLogin::start()`] for the regular path.
pub fn builder<'a, R: RngCore + CryptoRng, SK: Clone>( pub fn builder<'a, R: Rng + CryptoRng, SK: Clone>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS, SK>, server_setup: &ServerSetup<CS, SK>,
password_file: Option<ServerRegistration<CS>>, password_file: Option<ServerRegistration<CS>>,
@@ -747,7 +747,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
let credential_response = CredentialResponse { let credential_response = CredentialResponse {
evaluation_element: builder.evaluation_element.clone(), evaluation_element: builder.evaluation_element.clone(),
masking_nonce: *builder.masking_nonce.deref(), masking_nonce: *builder.masking_nonce,
masked_response: builder.masked_response.clone(), masked_response: builder.masked_response.clone(),
ke2_message: result.message, ke2_message: result.message,
}; };
@@ -762,13 +762,13 @@ impl<CS: CipherSuite> ServerLogin<CS> {
#[cfg(test)] #[cfg(test)]
server_mac_key: result.km2, server_mac_key: result.km2,
#[cfg(test)] #[cfg(test)]
oprf_key: builder.oprf_key.deref().clone(), oprf_key: (*builder.oprf_key).clone(),
}) })
} }
/// From the client's "blinded" password, returns a challenge to be sent /// From the client's "blinded" password, returns a challenge to be sent
/// back to the client, as well as a [`ServerLogin`] /// back to the client, as well as a [`ServerLogin`]
pub fn start<R: RngCore + CryptoRng>( pub fn start<R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
server_setup: &ServerSetup<CS>, server_setup: &ServerSetup<CS>,
password_file: Option<ServerRegistration<CS>>, password_file: Option<ServerRegistration<CS>>,
@@ -1004,21 +1004,22 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn get_password_derived_key<CS: CipherSuite>( fn get_password_derived_key<CS: CipherSuite>(
input: &[u8], input: &[u8],
oprf_client: voprf::OprfClient<CS::OprfCs>, oprf_client: OprfClient<CS::OprfCs>,
evaluation_element: voprf::EvaluationElement<CS::OprfCs>, evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
ksf: Option<&CS::Ksf>, ksf: Option<&CS::Ksf>,
) -> Result<(Output<OprfHash<CS>>, Hkdf<OprfHash<CS>>), ProtocolError> { ) -> Result<(Output<OprfHash<CS>>, hkdf::SimpleHkdf<OprfHash<CS>>), ProtocolError> {
let oprf_output = oprf_client.finalize(input, &evaluation_element)?; let oprf_output = oprf_client.finalize(input, &evaluation_element)?;
let oprf_ga = GenericArray::from_ha0_4(oprf_output.clone());
let hardened_output = if let Some(ksf) = ksf { let hardened_output = if let Some(ksf) = ksf {
ksf.hash(oprf_output.clone()) ksf.hash(oprf_ga.clone())
} else { } else {
CS::Ksf::default().hash(oprf_output.clone()) CS::Ksf::default().hash(oprf_ga.clone())
} }
.map_err(ProtocolError::from)?; .map_err(ProtocolError::from)?;
let mut hkdf = HkdfExtract::<OprfHash<CS>>::new(None); let mut hkdf = HkdfExtract::<OprfHash<CS>>::new(None);
hkdf.input_ikm(&oprf_output); hkdf.input_ikm(&oprf_ga);
hkdf.input_ikm(&hardened_output); hkdf.input_ikm(&hardened_output);
Ok(hkdf.finalize()) Ok(hkdf.finalize())
} }
@@ -1039,13 +1040,9 @@ fn oprf_key_material<CS: CipherSuite>(
fn oprf_key_from_key_material<CS: CipherSuite>( fn oprf_key_from_key_material<CS: CipherSuite>(
input: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, input: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
) -> Result<GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, InternalError> { ) -> Result<GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, InternalError> {
Ok(OprfGroup::<CS>::serialize_scalar(voprf::derive_key::< Ok(GenericArray::from_ha0_4(OprfGroup::<CS>::serialize_scalar(
CS::OprfCs, voprf::derive_key::<CS::OprfCs>(&input, STR_OPAQUE_DERIVE_KEY_PAIR, voprf::Mode::Oprf)?,
>( )))
input.as_slice(),
&GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
voprf::Mode::Oprf,
)?))
} }
#[cfg_attr( #[cfg_attr(
@@ -1066,19 +1063,28 @@ pub(crate) type MaskedResponseLen<CS: CipherSuite> =
impl<CS: CipherSuite> MaskedResponse<CS> { impl<CS: CipherSuite> MaskedResponse<CS> {
pub(crate) fn serialize(&self) -> GenericArray<u8, MaskedResponseLen<CS>> { pub(crate) fn serialize(&self) -> GenericArray<u8, MaskedResponseLen<CS>> {
self.nonce.concat_ext(&self.hash).concat(self.pk.clone()) let hash_ga: &GenericArray<u8, OutputSize<OprfHash<CS>>> =
} GenericArray::from_slice(self.hash.as_slice());
self.nonce.concat_ext(hash_ga).cat(self.pk.clone())
}
pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> { pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
Ok(Self { Ok(Self {
nonce: bytes.take_array("masked nonce")?, nonce: bytes.take_array("masked nonce")?,
hash: bytes.take_array("masked hash")?, hash: bytes
.take_array::<OutputSize<OprfHash<CS>>>("masked hash")?
.into_ha0_4(),
pk: bytes.take_array("masked public key")?, pk: bytes.take_array("masked public key")?,
}) })
} }
pub(crate) fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> { pub(crate) fn iter(&self) -> impl Clone + Iterator<Item = &[u8]> {
[self.nonce.as_slice(), &self.hash, &self.pk].into_iter() [
self.nonce.as_slice(),
self.hash.as_slice(),
self.pk.as_slice(),
]
.into_iter()
} }
} }
@@ -1105,7 +1111,9 @@ fn mask_response<CS: CipherSuite>(
*x1 ^= x2 *x1 ^= x2
} }
MaskedResponse::deserialize_take(&mut (xor_pad.as_slice())) let mut slice: &[u8] = &xor_pad;
MaskedResponse::deserialize_take(&mut (slice))
} }
fn unmask_response<CS: CipherSuite>( fn unmask_response<CS: CipherSuite>(
@@ -1124,7 +1132,7 @@ fn unmask_response<CS: CipherSuite>(
*x1 ^= x2 *x1 ^= x2
} }
let mut xor_pad = xor_pad.as_slice(); let mut xor_pad: &[u8] = xor_pad.as_ref();
let server_s_pk = let server_s_pk =
PublicKey::deserialize_take(&mut xor_pad).map_err(|_| ProtocolError::SerializationError)?; PublicKey::deserialize_take(&mut xor_pad).map_err(|_| ProtocolError::SerializationError)?;
let envelope = Envelope::deserialize_take(&mut xor_pad)?; let envelope = Envelope::deserialize_take(&mut xor_pad)?;
@@ -1135,12 +1143,12 @@ fn unmask_response<CS: CipherSuite>(
/// Internal function for computing the blind result by calling the voprf /// Internal function for computing the blind result by calling the voprf
/// library. Note that for tests, we use the deterministic blinding in order to /// library. Note that for tests, we use the deterministic blinding in order to
/// be able to set the blinding factor directly from the passed-in rng. /// be able to set the blinding factor directly from the passed-in rng.
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>( fn blind<CS: CipherSuite, R: Rng + CryptoRng>(
rng: &mut R, rng: &mut R,
password: &[u8], password: &[u8],
) -> Result<voprf::OprfClientBlindResult<CS::OprfCs>, voprf::Error> { ) -> Result<voprf::OprfClientBlindResult<CS::OprfCs>, voprf::Error> {
#[cfg(not(test))] #[cfg(not(test))]
let result = voprf::OprfClient::blind(password, rng)?; let result = OprfClient::blind(password, rng)?;
#[cfg(test)] #[cfg(test)]
let result = { let result = {
@@ -1152,7 +1160,7 @@ fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
break scalar; break scalar;
} }
}; };
voprf::OprfClient::deterministic_blind_unchecked(password, blind)? OprfClient::deterministic_blind_unchecked(password, blind)?
}; };
Ok(result) Ok(result)
+33 -17
View File
@@ -8,18 +8,16 @@
use core::ops::Add; use core::ops::Add;
use crate::errors::ProtocolError;
use digest::Update; use digest::Update;
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::Sum; use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hybrid_array::{Array, ArraySize};
use crate::errors::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>(input: usize) -> Result<GenericArray<u8, L>, ProtocolError> {
input: usize, const SIZEOF_USIZE: usize = size_of::<usize>();
) -> Result<GenericArray<u8, L>, ProtocolError> {
const SIZEOF_USIZE: usize = core::mem::size_of::<usize>();
// Make sure input fits in output. // Make sure input fits in output.
if (SIZEOF_USIZE as u32 - input.leading_zeros() / 8) > L::U32 { if (SIZEOF_USIZE as u32 - input.leading_zeros() / 8) > L::U32 {
@@ -35,12 +33,12 @@ pub(crate) fn i2osp<L: ArrayLength<u8>>(
// Corresponds to the OS2IP() function from RFC8017 // Corresponds to the OS2IP() function from RFC8017
#[cfg(test)] #[cfg(test)]
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, ProtocolError> { pub(crate) fn os2ip(input: &[u8]) -> Result<usize, ProtocolError> {
if input.len() > core::mem::size_of::<usize>() { if input.len() > size_of::<usize>() {
return Err(ProtocolError::SerializationError); return Err(ProtocolError::SerializationError);
} }
let mut output_array = [0u8; core::mem::size_of::<usize>()]; let mut output_array = [0u8; size_of::<usize>()];
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input); output_array[size_of::<usize>() - input.len()..].copy_from_slice(input);
Ok(usize::from_be_bytes(output_array)) Ok(usize::from_be_bytes(output_array))
} }
@@ -69,14 +67,14 @@ impl<T: Update> UpdateExt for T {
} }
pub(crate) trait SliceExt { pub(crate) trait SliceExt {
fn take_array<L: ArrayLength<u8>>( fn take_array<L: ArrayLength + ArraySize>(
self: &mut &Self, self: &mut &Self,
name: &'static str, name: &'static str,
) -> Result<GenericArray<u8, L>, ProtocolError>; ) -> Result<GenericArray<u8, L>, ProtocolError>;
} }
impl SliceExt for [u8] { impl SliceExt for [u8] {
fn take_array<L: ArrayLength<u8>>( fn take_array<L: ArrayLength + ArraySize>(
self: &mut &Self, self: &mut &Self,
name: &'static str, name: &'static str,
) -> Result<GenericArray<u8, L>, ProtocolError> { ) -> Result<GenericArray<u8, L>, ProtocolError> {
@@ -90,23 +88,24 @@ impl SliceExt for [u8] {
let (front, back) = self.split_at(L::USIZE); let (front, back) = self.split_at(L::USIZE);
*self = back; *self = back;
Ok(GenericArray::clone_from_slice(front)) let arr: Array<u8, L> = Array::try_from(front).unwrap();
Ok(GenericArray::from(arr))
} }
} }
pub(crate) trait GenericArrayExt<O: ArrayLength<u8>> { pub(crate) trait GenericArrayExt<O: ArrayLength> {
type Output: ArrayLength<u8>; type Output: ArrayLength;
/// This allows us to concat two [`GenericArray`]s but with `where` bounds /// This allows us to concat two [`GenericArray`]s but with `where` bounds
/// `Other + Self`. Because sometimes `Self + Other` doesn't imply the /// `Other + Self`. Because sometimes `Self + Other` doesn't imply the
/// bounds and we have to add them to every call. /// bounds, and we have to add them to every call.
fn concat_ext(&self, rest: &GenericArray<u8, O>) -> GenericArray<u8, Self::Output>; fn concat_ext(&self, rest: &GenericArray<u8, O>) -> GenericArray<u8, Self::Output>;
} }
impl<L: ArrayLength<u8>, O: ArrayLength<u8>> GenericArrayExt<O> for GenericArray<u8, L> impl<L: ArrayLength, O: ArrayLength> GenericArrayExt<O> for GenericArray<u8, L>
where where
O: Add<L>, O: Add<L>,
Sum<O, L>: ArrayLength<u8>, Sum<O, L>: ArrayLength,
{ {
type Output = Sum<O, L>; type Output = Sum<O, L>;
@@ -119,6 +118,23 @@ where
} }
} }
pub(crate) trait ConcatExt<N: ArrayLength>: Sized {
fn cat<M: ArrayLength>(self, other: GenericArray<u8, M>) -> GenericArray<u8, Sum<N, M>>
where
N: Add<M>,
Sum<N, M>: ArrayLength;
}
impl<N: ArrayLength> ConcatExt<N> for GenericArray<u8, N> {
fn cat<M: ArrayLength>(self, other: GenericArray<u8, M>) -> GenericArray<u8, Sum<N, M>>
where
N: Add<M>,
Sum<N, M>: ArrayLength,
{
Concat::concat(self, other)
}
}
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
+62 -63
View File
@@ -15,8 +15,9 @@ use generic_array::ArrayLength;
use generic_array::typenum::{Sum, Unsigned}; use generic_array::typenum::{Sum, Unsigned};
use proptest::collection::vec; use proptest::collection::vec;
use proptest::prelude::*; use proptest::prelude::*;
use rand::RngCore; use rand::Rng;
use rand::rngs::OsRng; use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use voprf::Group as _; use voprf::Group as _;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash}; use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
@@ -41,7 +42,7 @@ struct TripleDhRistretto255;
impl CipherSuite for TripleDhRistretto255 { impl CipherSuite for TripleDhRistretto255 {
type OprfCs = Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>; type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
#[cfg(all(feature = "ristretto255", feature = "curve25519"))] #[cfg(all(feature = "ristretto255", feature = "curve25519"))]
@@ -51,31 +52,31 @@ struct TripleDhCurve25519;
impl CipherSuite for TripleDhCurve25519 { impl CipherSuite for TripleDhCurve25519 {
type OprfCs = Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = TripleDh<Curve25519, sha2::Sha512>; type KeyExchange = TripleDh<Curve25519, sha2::Sha512>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
struct TripleDhP256; struct TripleDhP256;
impl CipherSuite for TripleDhP256 { impl CipherSuite for TripleDhP256 {
type OprfCs = ::p256::NistP256; type OprfCs = p256::NistP256;
type KeyExchange = TripleDh<::p256::NistP256, sha2::Sha256>; type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
struct TripleDhP384; struct TripleDhP384;
impl CipherSuite for TripleDhP384 { impl CipherSuite for TripleDhP384 {
type OprfCs = ::p384::NistP384; type OprfCs = p384::NistP384;
type KeyExchange = TripleDh<::p384::NistP384, sha2::Sha384>; type KeyExchange = TripleDh<p384::NistP384, sha2::Sha384>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
struct TripleDhP521; struct TripleDhP521;
impl CipherSuite for TripleDhP521 { impl CipherSuite for TripleDhP521 {
type OprfCs = ::p521::NistP521; type OprfCs = p521::NistP521;
type KeyExchange = TripleDh<::p521::NistP521, sha2::Sha512>; type KeyExchange = TripleDh<p521::NistP521, sha2::Sha512>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
@@ -83,10 +84,9 @@ struct SigmaIP256;
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
impl CipherSuite for SigmaIP256 { impl CipherSuite for SigmaIP256 {
type OprfCs = ::p256::NistP256; type OprfCs = p256::NistP256;
type KeyExchange = type KeyExchange = SigmaI<Ecdsa<p256::NistP256, sha2::Sha256>, p256::NistP256, sha2::Sha256>;
SigmaI<Ecdsa<::p256::NistP256, sha2::Sha256>, ::p256::NistP256, sha2::Sha256>; type Ksf = ksf::Identity;
type Ksf = crate::ksf::Identity;
} }
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
@@ -94,10 +94,9 @@ struct SigmaIP384;
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
impl CipherSuite for SigmaIP384 { impl CipherSuite for SigmaIP384 {
type OprfCs = ::p384::NistP384; type OprfCs = p384::NistP384;
type KeyExchange = type KeyExchange = SigmaI<Ecdsa<p384::NistP384, sha2::Sha384>, p384::NistP384, sha2::Sha384>;
SigmaI<Ecdsa<::p384::NistP384, sha2::Sha384>, ::p384::NistP384, sha2::Sha384>; type Ksf = ksf::Identity;
type Ksf = crate::ksf::Identity;
} }
#[cfg(all(feature = "ristretto255", feature = "ed25519",))] #[cfg(all(feature = "ristretto255", feature = "ed25519",))]
@@ -107,7 +106,7 @@ struct SigmaIEd25519;
impl CipherSuite for SigmaIEd25519 { impl CipherSuite for SigmaIEd25519 {
type OprfCs = Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = SigmaI<PureEddsa<Ed25519>, Ristretto255, sha2::Sha512>; type KeyExchange = SigmaI<PureEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
#[cfg(all(feature = "ristretto255", feature = "ed25519"))] #[cfg(all(feature = "ristretto255", feature = "ed25519"))]
@@ -117,19 +116,19 @@ struct SigmaIEd25519Ph;
impl CipherSuite for SigmaIEd25519Ph { impl CipherSuite for SigmaIEd25519Ph {
type OprfCs = Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = SigmaI<HashEddsa<Ed25519>, Ristretto255, sha2::Sha512>; type KeyExchange = SigmaI<HashEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
type Ksf = crate::ksf::Identity; type Ksf = ksf::Identity;
} }
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
fn random_point<CS: CipherSuite>() -> <KeGroup<CS> as Group>::Pk { fn random_point<CS: CipherSuite>() -> <KeGroup<CS> as Group>::Pk {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let sk = KeGroup::<CS>::random_sk(&mut rng); let sk = KeGroup::<CS>::random_sk(&mut rng);
KeGroup::<CS>::public_key(&sk) KeGroup::<CS>::public_key(&sk)
} }
fn random_element<CS: CipherSuite>() -> <OprfGroup<CS> as voprf::Group>::Elem { fn random_element<CS: CipherSuite>() -> <OprfGroup<CS> as voprf::Group>::Elem {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let scalar = OprfGroup::<CS>::random_scalar(&mut rng); let scalar = OprfGroup::<CS>::random_scalar(&mut rng).unwrap();
OprfGroup::<CS>::base_elem() * &scalar OprfGroup::<CS>::base_elem() * &scalar
} }
@@ -139,10 +138,10 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
where where
// ClientRegistration: KgSk + KgPk // ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>, ClientRegistrationLen<CS>: ArrayLength,
{ {
let pw = b"hunter2"; let pw = b"hunter2";
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let blind_result = &voprf::OprfClient::<CS::OprfCs>::blind(pw, &mut rng)?; let blind_result = &voprf::OprfClient::<CS::OprfCs>::blind(pw, &mut rng)?;
@@ -186,12 +185,12 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// 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 = UnwrapErr(SysRng);
let mut masking_key = Output::<OprfHash<CS>>::default(); let mut masking_key = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut masking_key); rng.fill_bytes(&mut masking_key);
@@ -287,11 +286,11 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
where where
// RegistrationResponse: KgPk + KePk // RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>, RegistrationResponseLen<CS>: ArrayLength,
{ {
let elem = random_element::<CS>(); let elem = random_element::<CS>();
let beta_bytes = OprfGroup::<CS>::serialize_elem(elem); let beta_bytes = OprfGroup::<CS>::serialize_elem(elem);
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let pubkey_bytes = skp.public().serialize(); let pubkey_bytes = skp.public().serialize();
@@ -345,10 +344,10 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let pubkey_bytes = skp.public().serialize(); let pubkey_bytes = skp.public().serialize();
@@ -360,15 +359,15 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
let mut masking_key = Output::<OprfHash<CS>>::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::SimpleHkdf::<OprfHash<CS>>::new(None, &key);
let (envelope, _, _) = Envelope::<CS>::seal_raw( let (envelope, _, _) = Envelope::<CS>::seal_raw(
randomized_pwd_hasher, &randomized_pwd_hasher,
nonce.into(), nonce.into(),
[pubkey_bytes.as_slice()].into_iter(), [pubkey_bytes.as_slice()].into_iter(),
InnerEnvelopeMode::Internal, InnerEnvelopeMode::Internal,
) )?;
.unwrap();
let envelope_bytes = envelope.serialize(); let envelope_bytes = envelope.serialize();
let mut input = Vec::new(); let mut input = Vec::new();
@@ -409,9 +408,9 @@ fn triple_dh_credential_request_roundtrip() -> Result<(), ProtocolError> {
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize,
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let alpha = random_element::<CS>(); let alpha = random_element::<CS>();
let alpha_bytes = OprfGroup::<CS>::serialize_elem(alpha); let alpha_bytes = OprfGroup::<CS>::serialize_elem(alpha);
@@ -466,17 +465,17 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
let elem = random_element::<CS>(); let elem = random_element::<CS>();
let elem_bytes = OprfGroup::<CS>::serialize_elem(elem); let elem_bytes = OprfGroup::<CS>::serialize_elem(elem);
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let mut masking_nonce = [0u8; 32]; let mut masking_nonce = [0u8; 32];
rng.fill_bytes(&mut masking_nonce); rng.fill_bytes(&mut masking_nonce);
@@ -504,7 +503,7 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> {
input.extend_from_slice(&masked_response); input.extend_from_slice(&masked_response);
input.extend_from_slice(&ke2m); input.extend_from_slice(&ke2m);
let l2 = CredentialResponse::<CS>::deserialize(&input).unwrap(); let l2 = CredentialResponse::<CS>::deserialize(&input)?;
let l2_bytes = l2.serialize(); let l2_bytes = l2.serialize();
assert_eq!(input, *l2_bytes); assert_eq!(input, *l2_bytes);
@@ -550,17 +549,17 @@ fn sigma_i_ecdsa_credential_response_roundtrip() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
let pt = random_point::<CS>(); let pt = random_point::<CS>();
let pt_bytes = KeGroup::<CS>::serialize_pk(&pt); let pt_bytes = KeGroup::<CS>::serialize_pk(&pt);
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let mut masking_nonce = [0u8; 32]; let mut masking_nonce = [0u8; 32];
rng.fill_bytes(&mut masking_nonce); rng.fill_bytes(&mut masking_nonce);
@@ -630,7 +629,7 @@ fn triple_dh_credential_finalization_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let mut mac = Output::<OprfHash<CS>>::default(); let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac); rng.fill_bytes(&mut mac);
@@ -661,7 +660,7 @@ fn sigma_i_ecdsa_credential_finalization_roundtrip() -> Result<(), ProtocolError
where where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng)); let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng)); let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
@@ -696,16 +695,16 @@ fn triple_dh_client_login_roundtrip() -> Result<(), ProtocolError> {
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State // ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize, <CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>: Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>, ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>, ClientLoginLen<CS>: ArrayLength,
{ {
let pw = b"hunter2"; let pw = b"hunter2";
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut client_nonce = [0; NonceLen::USIZE]; let mut client_nonce = [0; NonceLen::USIZE];
@@ -762,7 +761,7 @@ fn triple_dh_ke1_message_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let client_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut client_nonce = vec![0u8; NonceLen::USIZE]; let mut client_nonce = vec![0u8; NonceLen::USIZE];
@@ -798,7 +797,7 @@ fn triple_dh_ke2_message_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default(); let mut mac = Output::<OprfHash<CS>>::default();
@@ -839,7 +838,7 @@ fn sigma_i_ecdsa_ke2_message_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng); let server_e_kp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
let mut mac = Output::<OprfHash<CS>>::default(); let mut mac = Output::<OprfHash<CS>>::default();
@@ -878,7 +877,7 @@ fn triple_dh_ke3_message_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let mut mac = Output::<OprfHash<CS>>::default(); let mut mac = Output::<OprfHash<CS>>::default();
rng.fill_bytes(&mut mac); rng.fill_bytes(&mut mac);
@@ -910,7 +909,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
where where
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize, <CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
{ {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng)); let r = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng)); let s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
let mut mac = Output::<OprfHash<CS>>::default(); let mut mac = Output::<OprfHash<CS>>::default();
@@ -934,7 +933,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
proptest! { proptest! {
#[test] #[test]
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..core::mem::size_of::<usize>())) { fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..size_of::<usize>())) {
use generic_array::typenum::{U0, U1, U2, U3, U4, U5, U6, U7}; use generic_array::typenum::{U0, U1, U2, U3, U4, U5, U6, U7};
let input = os2ip(&bytes).unwrap(); let input = os2ip(&bytes).unwrap();
+78 -86
View File
@@ -19,8 +19,9 @@ use generic_array::{ArrayLength, GenericArray};
#[cfg(feature = "kem")] #[cfg(feature = "kem")]
use ml_kem::MlKem768; use ml_kem::MlKem768;
use rand::SeedableRng; use rand::SeedableRng;
use rand::rngs::OsRng; use rand::rngs::SysRng;
use rand_chacha::ChaCha20Rng; use rand_chacha::ChaCha20Rng;
use rand_core::UnwrapErr;
use serde_json::Value; use serde_json::Value;
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
use voprf::Group as _; use voprf::Group as _;
@@ -42,6 +43,7 @@ use crate::messages::{
RegistrationResponseLen, RegistrationUploadLen, RegistrationResponseLen, RegistrationUploadLen,
}; };
use crate::opaque::*; use crate::opaque::*;
use crate::tests::decode;
use crate::tests::mock_rng::CycleRng; use crate::tests::mock_rng::CycleRng;
use crate::*; use crate::*;
@@ -70,7 +72,7 @@ macro_rules! ciphersuite_types {
macro_rules! generate { macro_rules! generate {
($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($output:ident)) => { ($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($output:ident)) => {
paste::paste! { pastey::paste! {
$(#[$attr])* $(#[$attr])*
{ {
let parameters = generate_parameters::<$name>()?; let parameters = generate_parameters::<$name>()?;
@@ -89,7 +91,7 @@ macro_rules! generate {
macro_rules! run_all { macro_rules! run_all {
($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($fn:ident $(, $par:expr)*)) => { ($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($fn:ident $(, $par:expr)*)) => {
paste::paste! { pastey::paste! {
$(#[$attr])* $(#[$attr])*
$fn::<$name>(super::full_test_vectors::[<TEST_VECTOR_ $name:snake:upper>] $(, $par)*)?; $fn::<$name>(super::full_test_vectors::[<TEST_VECTOR_ $name:snake:upper>] $(, $par)*)?;
} }
@@ -118,7 +120,7 @@ macro_rules! oprf_ciphersuites {
#[$ke_attr_1:meta] #[$ke_attr_2:meta] [$ke_name:ident, $ke:ty], #[$ke_attr_1:meta] #[$ke_attr_2:meta] [$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => { ) => {
paste::paste! { pastey::paste! {
$($macro!(#[$ke_attr_1] #[$ke_attr_2] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ $($macro!(#[$ke_attr_1] #[$ke_attr_2] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
} }
}; };
@@ -127,7 +129,7 @@ macro_rules! oprf_ciphersuites {
#[$ke_attr:meta] [$ke_name:ident, $ke:ty], #[$ke_attr:meta] [$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => { ) => {
paste::paste! { pastey::paste! {
$($macro!(#[$ke_attr] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ $($macro!(#[$ke_attr] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
} }
}; };
@@ -136,7 +138,7 @@ macro_rules! oprf_ciphersuites {
[$ke_name:ident, $ke:ty], [$ke_name:ident, $ke:ty],
[$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?],
) => { ) => {
paste::paste! { pastey::paste! {
$($macro!($(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ $($macro!($(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+
} }
} }
@@ -196,7 +198,7 @@ macro_rules! sigma_i_ciphersuites {
$macro:ident!$par:tt => $macro:ident!$par:tt =>
[$($(#[$sig_attr:meta])? [$sig_name:ident, $sig:ty]),+$(,)?], [$($(#[$sig_attr:meta])? [$sig_name:ident, $sig:ty]),+$(,)?],
) => { ) => {
paste::paste! { pastey::paste! {
$( $(
oprf_ciphersuites!( oprf_ciphersuites!(
$macro!$par => [ $macro!$par => [
@@ -261,10 +263,6 @@ pub struct TestVectorParameters {
static STR_PASSWORD: &str = "password"; static STR_PASSWORD: &str = "password";
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
fn populate_test_vectors(values: &Value) -> TestVectorParameters { fn populate_test_vectors(values: &Value) -> TestVectorParameters {
TestVectorParameters { TestVectorParameters {
client_s_pk: decode(values, "client_s_pk").unwrap(), client_s_pk: decode(values, "client_s_pk").unwrap(),
@@ -521,37 +519,37 @@ where
<CS::KeyExchange as KeyExchange>::KE3Message: Serialize, <CS::KeyExchange as KeyExchange>::KE3Message: Serialize,
// ClientRegistration: KgSk + KgPk // ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>, ClientRegistrationLen<CS>: ArrayLength,
// RegistrationResponse: KgPk + KePk // RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>, RegistrationResponseLen<CS>: ArrayLength,
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State // ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize, <CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>: Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>, ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>, ClientLoginLen<CS>: ArrayLength,
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
use rand::RngCore; use rand::Rng;
use crate::keypair::KeyPair; use crate::keypair::KeyPair;
@@ -588,20 +586,19 @@ where
let dummy_client_pk = dummy_client_pk.serialize(); let dummy_client_pk = dummy_client_pk.serialize();
let server_setup = ServerSetup::<CS>::deserialize( let server_setup = ServerSetup::<CS>::deserialize(
&[ &[
oprf_seed.as_ref(), oprf_seed.as_slice(),
&server_s_kp.private().serialize(), server_s_kp.private().serialize().as_slice(),
&dummy_client_pk, dummy_client_pk.as_slice(),
] ]
.concat(), .concat(),
) )?;
.unwrap();
let blinding_factor = <OprfGroup<CS> as voprf::Group>::random_scalar(&mut rng); let blinding_factor = <OprfGroup<CS> as voprf::Group>::random_scalar(&mut rng)?;
let blinding_factor_bytes = OprfGroup::<CS>::serialize_scalar(blinding_factor); let blinding_factor_bytes = OprfGroup::<CS>::serialize_scalar(blinding_factor);
let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec()); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec());
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password).unwrap(); ClientRegistration::<CS>::start(&mut blinding_factor_registration_rng, password)?;
let blinding_factor_bytes_returned = OprfGroup::<CS>::serialize_scalar( let blinding_factor_bytes_returned = OprfGroup::<CS>::serialize_scalar(
client_registration_start_result client_registration_start_result
.state .state
@@ -620,8 +617,8 @@ where
&server_setup, &server_setup,
client_registration_start_result.message, client_registration_start_result.message,
credential_identifier, credential_identifier,
) )?;
.unwrap();
let registration_response_bytes = server_registration_start_result.message.serialize(); let registration_response_bytes = server_registration_start_result.message.serialize();
let mut client_s_sk_and_nonce: Vec<u8> = Vec::new(); let mut client_s_sk_and_nonce: Vec<u8> = Vec::new();
@@ -629,21 +626,18 @@ where
client_s_sk_and_nonce.extend_from_slice(&envelope_nonce); client_s_sk_and_nonce.extend_from_slice(&envelope_nonce);
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce); let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
let client_registration_finish_result = client_registration_start_result let client_registration_finish_result = client_registration_start_result.state.finish(
.state &mut finish_registration_rng,
.finish( password,
&mut finish_registration_rng, server_registration_start_result.message,
password, ClientRegistrationFinishParameters::new(
server_registration_start_result.message, Identifiers {
ClientRegistrationFinishParameters::new( client: Some(id_u),
Identifiers { server: Some(id_s),
client: Some(id_u), },
server: Some(id_s), None,
}, ),
None, )?;
),
)
.unwrap();
let registration_upload_bytes = client_registration_finish_result.message.serialize(); let registration_upload_bytes = client_registration_finish_result.message.serialize();
let password_file = ServerRegistration::finish(client_registration_finish_result.message); let password_file = ServerRegistration::finish(client_registration_finish_result.message);
@@ -656,7 +650,7 @@ where
let mut client_login_start_rng = CycleRng::new(client_login_start); let mut client_login_start_rng = CycleRng::new(client_login_start);
let client_login_start_result = let client_login_start_result =
ClientLogin::<CS>::start(&mut client_login_start_rng, password).unwrap(); ClientLogin::<CS>::start(&mut client_login_start_rng, password)?;
let credential_request_bytes = client_login_start_result.message.serialize(); let credential_request_bytes = client_login_start_result.message.serialize();
let client_login_state = client_login_start_result.state.serialize().to_vec(); let client_login_state = client_login_start_result.state.serialize().to_vec();
@@ -683,27 +677,23 @@ where
server: Some(id_s), server: Some(id_s),
}, },
}, },
) )?;
.unwrap();
let credential_response_bytes = server_login_start_result.message.serialize(); let credential_response_bytes = server_login_start_result.message.serialize();
let server_login_state = server_login_start_result.state.serialize(); let server_login_state = server_login_start_result.state.serialize();
let client_login_finish_result = client_login_start_result let client_login_finish_result = client_login_start_result.state.finish(
.state &mut CycleRng::new(client_sig_rng.to_vec()),
.finish( password,
&mut CycleRng::new(client_sig_rng.to_vec()), server_login_start_result.message,
password, ClientLoginFinishParameters::new(
server_login_start_result.message, Some(context),
ClientLoginFinishParameters::new( Identifiers {
Some(context), client: Some(id_u),
Identifiers { server: Some(id_s),
client: Some(id_u), },
server: Some(id_s), None,
}, ),
None, )?;
),
)
.unwrap();
let credential_finalization_bytes = client_login_finish_result.message.serialize(); let credential_finalization_bytes = client_login_finish_result.message.serialize();
Ok(TestVectorParameters { Ok(TestVectorParameters {
@@ -787,7 +777,7 @@ fn test_registration_request() -> Result<(), ProtocolError> {
where where
// ClientRegistration: KgSk + KgPk // ClientRegistration: KgSk + KgPk
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
ClientRegistrationLen<CS>: ArrayLength<u8>, ClientRegistrationLen<CS>: ArrayLength,
{ {
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
let mut rng = CycleRng::new(parameters.blinding_factor.to_vec()); let mut rng = CycleRng::new(parameters.blinding_factor.to_vec());
@@ -822,14 +812,16 @@ fn test_serialization() -> Result<(), ProtocolError> {
ClientRegistration::<CS>::start(&mut rng, &parameters.password)?; ClientRegistration::<CS>::start(&mut rng, &parameters.password)?;
// Test the bincode serialization (binary). // Test the bincode serialization (binary).
let cfg = bincode_next::config::standard();
let registration_request = let registration_request =
bincode::serialize(&client_registration_start_result.message).unwrap(); bincode_next::serde::encode_to_vec(&client_registration_start_result.message, cfg)
.unwrap();
assert_eq!( assert_eq!(
registration_request.len(), registration_request.len(),
RegistrationRequestLen::<CS>::USIZE RegistrationRequestLen::<CS>::USIZE
); );
let registration_request: RegistrationRequest<CS> = let (registration_request, _): (RegistrationRequest<CS>, usize) =
bincode::deserialize(&registration_request).unwrap(); bincode_next::serde::decode_from_slice(&registration_request, cfg).unwrap();
assert_eq!( assert_eq!(
hex::encode(client_registration_start_result.message.serialize()), hex::encode(client_registration_start_result.message.serialize()),
hex::encode(registration_request.serialize()), hex::encode(registration_request.serialize()),
@@ -852,7 +844,7 @@ fn test_registration_response() -> Result<(), ProtocolError> {
where where
// RegistrationResponse: KgPk + KePk // RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>, RegistrationResponseLen<CS>: ArrayLength,
{ {
let parameters = populate_test_vectors( let parameters = populate_test_vectors(
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
@@ -894,8 +886,8 @@ fn test_registration_upload() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
{ {
let parameters = populate_test_vectors( let parameters = populate_test_vectors(
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
@@ -945,8 +937,8 @@ fn test_password_file() -> Result<(), ProtocolError> {
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
{ {
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -977,13 +969,13 @@ fn test_credential_request() -> Result<(), ProtocolError> {
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
// ClientLogin: KgSk + CredentialRequest + Ke1State // ClientLogin: KgSk + CredentialRequest + Ke1State
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>, <OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
<CS::KeyExchange as KeyExchange>::KE1State: Serialize, <CS::KeyExchange as KeyExchange>::KE1State: Serialize,
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>: Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
ArrayLength<u8> + Add<Ke1StateLen<CS>>, ArrayLength + Add<Ke1StateLen<CS>>,
ClientLoginLen<CS>: ArrayLength<u8>, ClientLoginLen<CS>: ArrayLength,
{ {
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -1024,12 +1016,12 @@ fn test_credential_response() -> Result<(), ProtocolError> {
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
@@ -1182,8 +1174,8 @@ fn test_complete_flow<CS: CipherSuite>(
login_password: &[u8], login_password: &[u8],
) -> Result<(), ProtocolError> { ) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier"; let credential_identifier = b"credentialIdentifier";
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = OsRng; let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng); let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, registration_password)?; ClientRegistration::<CS>::start(&mut client_rng, registration_password)?;
@@ -1330,8 +1322,8 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> { fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier"; let credential_identifier = b"credentialIdentifier";
let password = b"password"; let password = b"password";
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = OsRng; let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng); let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, password)?; ClientRegistration::<CS>::start(&mut client_rng, password)?;
@@ -1377,8 +1369,8 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> {
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> { fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
let credential_identifier = b"credentialIdentifier"; let credential_identifier = b"credentialIdentifier";
let password = b"password"; let password = b"password";
let mut client_rng = OsRng; let mut client_rng = UnwrapErr(SysRng);
let mut server_rng = OsRng; let mut server_rng = UnwrapErr(SysRng);
let server_setup = ServerSetup::<CS>::new(&mut server_rng); let server_setup = ServerSetup::<CS>::new(&mut server_rng);
let client_registration_start_result = let client_registration_start_result =
ClientRegistration::<CS>::start(&mut client_rng, password)?; ClientRegistration::<CS>::start(&mut client_rng, password)?;
+24 -17
View File
@@ -9,9 +9,10 @@
use core::cmp::min; use core::cmp::min;
use std::vec::Vec; use std::vec::Vec;
use rand::{CryptoRng, Error, RngCore}; use core::convert::Infallible;
use rand_core::{TryCryptoRng, TryRng};
/// A simple implementation of `RngCore` for testing purposes. /// A simple implementation of `Rng` for testing purposes.
/// ///
/// This generates a cyclic sequence (i.e. cycles over an initial buffer) /// This generates a cyclic sequence (i.e. cycles over an initial buffer)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -38,29 +39,35 @@ fn rotate_left<T>(data: &mut [T], steps: usize) {
data.reverse(); data.reverse();
} }
impl RngCore for CycleRng { impl TryRng for CycleRng {
fn next_u32(&mut self) -> u32 { type Error = Infallible;
unimplemented!()
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
let mut buf = [0u8; 4];
self.try_fill_bytes(&mut buf)?;
Ok(u32::from_le_bytes(buf))
} }
#[inline] fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
fn next_u64(&mut self) -> u64 { let mut buf = [0u8; 8];
unimplemented!()
self.try_fill_bytes(&mut buf)?;
Ok(u64::from_le_bytes(buf))
} }
#[inline] fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
fn fill_bytes(&mut self, dest: &mut [u8]) {
let len = min(self.v.len(), dest.len()); let len = min(self.v.len(), dest.len());
dest[..len].copy_from_slice(&self.v[..len]);
rotate_left(&mut self.v, len);
}
#[inline] dest[..len].copy_from_slice(&self.v[..len]);
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest); rotate_left(&mut self.v, len);
Ok(()) Ok(())
} }
} }
// This is meant for testing only // This is meant for testing only
impl CryptoRng for CycleRng {} impl TryCryptoRng for CycleRng {}
+7
View File
@@ -6,6 +6,9 @@
// of this source tree. You may select, at your option, one of the above-listed // of this source tree. You may select, at your option, one of the above-listed
// licenses. // licenses.
use serde_json::Value;
use std::vec::Vec;
mod full_test; mod full_test;
#[rustfmt::skip] #[rustfmt::skip]
#[allow(dead_code)] #[allow(dead_code)]
@@ -14,3 +17,7 @@ pub mod mock_rng;
mod parser; mod parser;
mod rfc9807_vectors; mod rfc9807_vectors;
mod test_opaque_vectors; mod test_opaque_vectors;
pub(crate) fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
+4 -8
View File
@@ -15,20 +15,18 @@ pub(crate) fn rfc_to_json(input: &str) -> String {
} }
fn parse_vector_types(input: &str) -> String { fn parse_vector_types(input: &str) -> String {
let re = regex::Regex::new(r" (?P<type>.+?) Test Vectors").unwrap(); let re = regex::Regex::new(r" {2}(?P<type>.+?) Test Vectors").unwrap();
let mut vector_types = vec![]; let mut vector_types = vec![];
let chunks: Vec<&str> = re.split(input).collect(); let chunks: Vec<&str> = re.split(input).collect();
let mut count = 1; for (count, caps) in (1..).zip(re.captures_iter(input)) {
for caps in re.captures_iter(input) {
let vector_type = format!( let vector_type = format!(
"\"{}\": [\n {} \n]", "\"{}\": [\n {} \n]",
&caps["type"].trim(), &caps["type"].trim(),
parse_ciphersuites(chunks[count]) parse_ciphersuites(chunks[count])
); );
vector_types.push(vector_type); vector_types.push(vector_type);
count += 1;
} }
vector_types.join(",\n") vector_types.join(",\n")
@@ -36,15 +34,14 @@ fn parse_vector_types(input: &str) -> String {
fn parse_ciphersuites(input: &str) -> String { fn parse_ciphersuites(input: &str) -> String {
let re = regex::Regex::new( let re = regex::Regex::new(
r" Configuration\n(.|\n)*?OPRF: (?P<oprf>.*?)\n(.|\n)*?Group: (?P<group>.*?)\n", r" Configuration\n([\s\S])*?OPRF: (?P<oprf>.*?)\n([\s\S])*?Group: (?P<group>.*?)\n",
) )
.unwrap(); .unwrap();
let mut ciphersuites = vec![]; let mut ciphersuites = vec![];
let chunks: Vec<&str> = re.split(input).collect(); let chunks: Vec<&str> = re.split(input).collect();
let mut count = 1; for (count, caps) in (1..).zip(re.captures_iter(input)) {
for caps in re.captures_iter(input) {
let ciphersuite = format!( let ciphersuite = format!(
"{{ \"{}, {}\": {{ {} }} }}", "{{ \"{}, {}\": {{ {} }} }}",
&caps["oprf"], &caps["oprf"],
@@ -52,7 +49,6 @@ fn parse_ciphersuites(input: &str) -> String {
parse_params(chunks[count]) parse_params(chunks[count])
); );
ciphersuites.push(ciphersuite); ciphersuites.push(ciphersuite);
count += 1;
} }
ciphersuites.join(",\n") ciphersuites.join(",\n")
+34 -35
View File
@@ -10,13 +10,6 @@ use core::ops::Add;
use std::vec; use std::vec;
use std::vec::Vec; use std::vec::Vec;
use digest::OutputSizeUser;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use rand::RngCore;
use rand::rngs::OsRng;
use serde_json::Value;
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash}; use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
use crate::envelope::EnvelopeLen; use crate::envelope::EnvelopeLen;
use crate::errors::*; use crate::errors::*;
@@ -30,8 +23,16 @@ use crate::messages::{
RegistrationResponseLen, RegistrationUploadLen, RegistrationResponseLen, RegistrationUploadLen,
}; };
use crate::opaque::*; use crate::opaque::*;
use crate::tests::decode;
use crate::tests::mock_rng::CycleRng; use crate::tests::mock_rng::CycleRng;
use crate::*; use crate::*;
use digest::OutputSizeUser;
use generic_array::typenum::Sum;
use generic_array::{ArrayLength, GenericArray};
use rand::Rng;
use rand::rngs::SysRng;
use rand_core::UnwrapErr;
use serde_json::Value;
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[derive(Debug)] #[derive(Debug)]
@@ -87,19 +88,15 @@ macro_rules! parse_default {
}; };
} }
fn decode(values: &Value, key: &str) -> Option<Vec<u8>> {
values[key].as_str().and_then(|s| hex::decode(s).ok())
}
fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> OpaqueTestVectorParameters { fn populate_test_vectors<CS: CipherSuite>(values: &Value) -> OpaqueTestVectorParameters {
let mut rng = OsRng; let mut rng = UnwrapErr(SysRng);
OpaqueTestVectorParameters { OpaqueTestVectorParameters {
dummy_public_key: { dummy_public_key: {
match decode(values, "client_public_key") { decode(values, "client_public_key").unwrap_or_else(|| {
Some(value) => value, KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut UnwrapErr(SysRng)))
None => KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut OsRng)).to_vec(), .to_vec()
} })
}, },
dummy_masking_key: { dummy_masking_key: {
match decode(values, "masking_key") { match decode(values, "masking_key") {
@@ -151,8 +148,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
{ {
let password_file = ServerRegistration::<CS>::finish( let password_file = ServerRegistration::<CS>::finish(
@@ -185,12 +182,14 @@ fn tests() -> Result<(), ProtocolError> {
serde_json::from_str(super::parser::rfc_to_json(super::rfc9807_vectors::VECTORS).as_str()) serde_json::from_str(super::parser::rfc_to_json(super::rfc9807_vectors::VECTORS).as_str())
.expect("Could not parse json"); .expect("Could not parse json");
std::eprintln!("{}", serde_json::to_string_pretty(&rfc).unwrap());
#[cfg(feature = "ristretto255")] #[cfg(feature = "ristretto255")]
{ {
struct Ristretto255Sha512NoKsf; struct Ristretto255Sha512NoKsf;
impl CipherSuite for Ristretto255Sha512NoKsf { impl CipherSuite for Ristretto255Sha512NoKsf {
type OprfCs = crate::Ristretto255; type OprfCs = Ristretto255;
type KeyExchange = TripleDh<crate::Ristretto255, sha2::Sha512>; type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
type Ksf = Identity; type Ksf = Identity;
} }
@@ -331,7 +330,7 @@ fn test_registration_response<CS: CipherSuite>(
where where
// RegistrationResponse: KgPk + KePk // RegistrationResponse: KgPk + KePk
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
RegistrationResponseLen<CS>: ArrayLength<u8>, RegistrationResponseLen<CS>: ArrayLength,
{ {
for parameters in tvs { for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize( let server_setup = ServerSetup::<CS>::deserialize(
@@ -370,8 +369,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
{ {
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());
@@ -417,7 +416,7 @@ where
// CredentialRequest: KgPk + Ke1Message // CredentialRequest: KgPk + Ke1Message
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize, <CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
CredentialRequestLen<CS>: ArrayLength<u8>, CredentialRequestLen<CS>: ArrayLength,
{ {
for parameters in tvs { for parameters in tvs {
let client_login_start = [ let client_login_start = [
@@ -444,18 +443,18 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
for parameters in tvs { for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize( let server_setup = ServerSetup::<CS>::deserialize(
@@ -530,7 +529,7 @@ where
ClientLogin::<CS>::start(&mut client_login_start_rng, &parameters.password)?; ClientLogin::<CS>::start(&mut client_login_start_rng, &parameters.password)?;
let client_login_finish_result = client_login_start_result.state.finish( let client_login_finish_result = client_login_start_result.state.finish(
&mut OsRng, &mut UnwrapErr(SysRng),
&parameters.password, &parameters.password,
CredentialResponse::<CS>::deserialize(&parameters.KE2)?, CredentialResponse::<CS>::deserialize(&parameters.KE2)?,
ClientLoginFinishParameters::new( ClientLoginFinishParameters::new(
@@ -576,8 +575,8 @@ where
// RegistrationUpload: (KePk + Hash) + Envelope // RegistrationUpload: (KePk + Hash) + Envelope
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>, <KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>: Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
ArrayLength<u8> + Add<EnvelopeLen<CS>>, ArrayLength + Add<EnvelopeLen<CS>>,
RegistrationUploadLen<CS>: ArrayLength<u8>, RegistrationUploadLen<CS>: ArrayLength,
// ServerRegistration = RegistrationUpload // ServerRegistration = RegistrationUpload
{ {
for parameters in tvs { for parameters in tvs {
@@ -644,12 +643,12 @@ where
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>, <OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>: Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
ArrayLength<u8> + Add<MaskedResponseLen<CS>>, ArrayLength + Add<MaskedResponseLen<CS>>,
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>, CredentialResponseWithoutKeLen<CS>: ArrayLength,
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize, <CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>, CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
CredentialResponseLen<CS>: ArrayLength<u8>, CredentialResponseLen<CS>: ArrayLength,
{ {
for parameters in tvs { for parameters in tvs {
let server_setup = ServerSetup::<CS>::deserialize( let server_setup = ServerSetup::<CS>::deserialize(
-112
View File
@@ -1,112 +0,0 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
//
// This source code is dual-licensed under either the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree or the Apache
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree. You may select, at your option, one of the above-listed
// licenses.
use digest::OutputSizeUser;
use generic_array::GenericArray;
use generic_array::sequence::{Concat, Split};
use generic_array::typenum::Sum;
use opaque_ke::ksf::Identity;
use opaque_ke::{CipherSuite, ClientLogin, ServerLogin, ServerRegistration, ServerSetup, TripleDh};
use opaque_ke_3::key_exchange::group::KeGroup as v3KeGroup;
use opaque_ke_3::key_exchange::tripledh::TripleDh as v3TripleDh;
use opaque_ke_3::keypair::KeyPair;
use opaque_ke_3::ksf::Identity as v3Identity;
use opaque_ke_3::{
CipherSuite as v3CipherSuite, ClientRegistration as v3ClientRegistration,
ServerRegistration as v3ServerRegistration, ServerSetup as v3ServerSetup,
};
use p256::NistP256;
use rand::rngs::OsRng;
use sha2::Sha256;
const PASSWORD: &[u8] = b"test password";
const CLIENT_IDENTIFIER: &[u8] = b"test client identifier";
struct OldCipherSuite;
impl v3CipherSuite for OldCipherSuite {
type OprfCs = NistP256;
type KeGroup = NistP256;
type KeyExchange = v3TripleDh;
type Ksf = v3Identity;
}
struct NewCipherSuite;
impl CipherSuite for NewCipherSuite {
type OprfCs = NistP256;
type KeyExchange = TripleDh<NistP256, Sha256>;
type Ksf = Identity;
}
#[test]
fn registration_upload() {
// V3 registration.
let result = v3ClientRegistration::<OldCipherSuite>::start(&mut OsRng, PASSWORD).unwrap();
let client = result.state;
let old_server_setup = v3ServerSetup::<OldCipherSuite>::new(&mut OsRng);
let response =
v3ServerRegistration::start(&old_server_setup, result.message, CLIENT_IDENTIFIER)
.unwrap()
.message;
let upload = client
.finish(&mut OsRng, PASSWORD, response, Default::default())
.unwrap()
.message;
let old_registration = v3ServerRegistration::finish(upload);
// `ServerSetup` migration.
let server_setup = {
let old_serialized = old_server_setup.serialize();
type OldSeedLen = <<<OldCipherSuite as v3CipherSuite>::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize;
type OldSkLen = <<OldCipherSuite as v3CipherSuite>::KeGroup as v3KeGroup>::SkLen;
let (old_serialied_rest, old_fake_keypair_serialized): (
GenericArray<u8, Sum<OldSeedLen, OldSkLen>>,
_,
) = old_serialized.split();
let old_fake_keypair =
KeyPair::<<OldCipherSuite as v3CipherSuite>::KeGroup>::from_private_key_slice(
&old_fake_keypair_serialized,
)
.unwrap();
let old_fake_pk_serialized = old_fake_keypair.public().serialize();
let new_serialized = old_serialied_rest.concat(old_fake_pk_serialized);
ServerSetup::<NewCipherSuite>::deserialize(&new_serialized).unwrap()
};
// `ServerRegistration` migration.
let old_registration_serialized = old_registration.serialize();
let registration =
ServerRegistration::<NewCipherSuite>::deserialize(&old_registration_serialized).unwrap();
// Check if new `ServerRegistration` still works.
let result = ClientLogin::<NewCipherSuite>::start(&mut OsRng, PASSWORD).unwrap();
let client = result.state;
let result = ServerLogin::start(
&mut OsRng,
&server_setup,
Some(registration),
result.message,
CLIENT_IDENTIFIER,
Default::default(),
)
.unwrap();
let server = result.state;
let result = client
.finish(&mut OsRng, PASSWORD, result.message, Default::default())
.unwrap();
server.finish(result.message, Default::default()).unwrap();
}
+12 -12
View File
@@ -36,27 +36,27 @@ use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, Tag, ToEncodedPoint};
use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytesSize, Group as _, ProjectivePoint}; use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytesSize, Group as _, ProjectivePoint};
use generic_array::typenum::Unsigned; use generic_array::typenum::Unsigned;
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use opaque_ke::key_exchange::KeyExchange; use opaque_vx::key_exchange::KeyExchange;
use opaque_ke::key_exchange::group::Group; use opaque_vx::key_exchange::group::Group;
#[cfg(all(feature = "ristretto255", feature = "ed25519"))] #[cfg(all(feature = "ristretto255", feature = "ed25519"))]
use opaque_ke::key_exchange::group::ed25519::{self, Ed25519}; use opaque_vx::key_exchange::group::ed25519::{self, Ed25519};
use opaque_ke::key_exchange::group::elliptic_curve::NonIdentity; use opaque_vx::key_exchange::group::elliptic_curve::NonIdentity;
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
use opaque_ke::key_exchange::sigma_i::ecdsa::{self, Ecdsa, PreHash}; use opaque_vx::key_exchange::sigma_i::ecdsa::{self, Ecdsa, PreHash};
#[cfg(all(feature = "ristretto255", feature = "ed25519"))] #[cfg(all(feature = "ristretto255", feature = "ed25519"))]
use opaque_ke::key_exchange::sigma_i::pure_eddsa::PureEddsa; use opaque_vx::key_exchange::sigma_i::pure_eddsa::PureEddsa;
#[cfg(feature = "ecdsa")] #[cfg(feature = "ecdsa")]
use opaque_ke::key_exchange::sigma_i::{CachedMessage, HashOutput, Message, SigmaI}; use opaque_vx::key_exchange::sigma_i::{CachedMessage, HashOutput, Message, SigmaI};
use opaque_ke::key_exchange::tripledh::TripleDh; use opaque_vx::key_exchange::tripledh::TripleDh;
use opaque_ke::keypair::{KeyPair, PublicKey}; use opaque_vx::keypair::{KeyPair, PublicKey};
use opaque_ke::ksf::Identity; use opaque_vx::ksf::Identity;
use opaque_ke::{ use opaque_vx::{
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginStartResult, CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginStartResult,
ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationStartResult, ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationStartResult,
ServerLogin, ServerLoginParameters, ServerLoginStartResult, ServerRegistration, ServerSetup, ServerLogin, ServerLoginParameters, ServerLoginStartResult, ServerRegistration, ServerSetup,
}; };
#[cfg(all(feature = "curve25519", feature = "ristretto255"))] #[cfg(all(feature = "curve25519", feature = "ristretto255"))]
use opaque_ke::{Curve25519, Ristretto255}; use opaque_vx::{Curve25519, Ristretto255};
use p256::NistP256; use p256::NistP256;
use p384::NistP384; use p384::NistP384;
use p521::NistP521; use p521::NistP521;