feat: upgrade crypto ecosystem to latest RustCrypto stack
Rust CI / cargo fmt (pull_request) Successful in 13s
Rust CI / test (1.88.0 / no backend / no frontend) (pull_request) Failing after 13s
Rust CI / cargo clippy (pull_request) Successful in 1m23s
Rust CI / test (stable / no backend / no frontend) (pull_request) Successful in 2m18s
Rust CI / test (1.88.0 / no backend / --features argon2) (pull_request) Failing after 3s
Rust CI / test (stable / no backend / --features argon2) (pull_request) Successful in 2m27s
Rust CI / test (stable / no backend / --features serde) (pull_request) Successful in 2m48s
Rust CI / test (1.88.0 / no backend / --features serde) (pull_request) Failing after 4s
Rust CI / test (1.88.0 / --features curve25519 / no frontend) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / no frontend) (pull_request) Successful in 2m23s
Rust CI / test (1.88.0 / --features curve25519 / --features argon2) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / --features argon2) (pull_request) Successful in 2m32s
Rust CI / test (1.88.0 / --features curve25519 / --features serde) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / --features serde) (pull_request) Successful in 2m50s
Rust CI / test (stable / --features ecdsa / no frontend) (pull_request) Successful in 2m44s
Rust CI / test (1.88.0 / --features ecdsa / no frontend) (pull_request) Failing after 4s
Rust CI / test (1.88.0 / --features ecdsa / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ecdsa / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ecdsa / --features argon2) (pull_request) Failing after 3s
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / --features serde) (pull_request) Has been cancelled
Rust CI / test simple_login example (pull_request) Has been cancelled
Rust CI / test digital_locker example (pull_request) Has been cancelled
Rust CI / cargo bench compilation () (pull_request) Has been cancelled
Rust CI / cargo bench compilation (--features ristretto255) (pull_request) Has been cancelled
Rust CI / cargo bench compilation (--features ristretto255,kem) (pull_request) Has been cancelled
Rust CI / cargo audit (pull_request) Has been cancelled
Rust CI / test (stable / --features ecdsa / --features argon2) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ristretto255,curve25519,ecdsa,ed25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / no backend) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / no backend) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / curve25519) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / curve25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ecdsa) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ecdsa) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ed25519) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ed25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ristretto255) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ristretto255) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ristretto255,curve25519,ecdsa,ed25519) (pull_request) Has been cancelled
Rust CI / cargo fmt (pull_request) Successful in 13s
Rust CI / test (1.88.0 / no backend / no frontend) (pull_request) Failing after 13s
Rust CI / cargo clippy (pull_request) Successful in 1m23s
Rust CI / test (stable / no backend / no frontend) (pull_request) Successful in 2m18s
Rust CI / test (1.88.0 / no backend / --features argon2) (pull_request) Failing after 3s
Rust CI / test (stable / no backend / --features argon2) (pull_request) Successful in 2m27s
Rust CI / test (stable / no backend / --features serde) (pull_request) Successful in 2m48s
Rust CI / test (1.88.0 / no backend / --features serde) (pull_request) Failing after 4s
Rust CI / test (1.88.0 / --features curve25519 / no frontend) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / no frontend) (pull_request) Successful in 2m23s
Rust CI / test (1.88.0 / --features curve25519 / --features argon2) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / --features argon2) (pull_request) Successful in 2m32s
Rust CI / test (1.88.0 / --features curve25519 / --features serde) (pull_request) Failing after 4s
Rust CI / test (stable / --features curve25519 / --features serde) (pull_request) Successful in 2m50s
Rust CI / test (stable / --features ecdsa / no frontend) (pull_request) Successful in 2m44s
Rust CI / test (1.88.0 / --features ecdsa / no frontend) (pull_request) Failing after 4s
Rust CI / test (1.88.0 / --features ecdsa / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ecdsa / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ecdsa / --features argon2) (pull_request) Failing after 3s
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,curve25519,ecdsa,ed25519 / --features serde) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / no frontend) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / no frontend) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / --features argon2) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / --features argon2) (pull_request) Has been cancelled
Rust CI / test (1.88.0 / --features ristretto255,kem / --features serde) (pull_request) Has been cancelled
Rust CI / test (stable / --features ristretto255,kem / --features serde) (pull_request) Has been cancelled
Rust CI / test simple_login example (pull_request) Has been cancelled
Rust CI / test digital_locker example (pull_request) Has been cancelled
Rust CI / cargo bench compilation () (pull_request) Has been cancelled
Rust CI / cargo bench compilation (--features ristretto255) (pull_request) Has been cancelled
Rust CI / cargo bench compilation (--features ristretto255,kem) (pull_request) Has been cancelled
Rust CI / cargo audit (pull_request) Has been cancelled
Rust CI / test (stable / --features ecdsa / --features argon2) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ristretto255,curve25519,ecdsa,ed25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / no backend) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / no backend) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / curve25519) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / curve25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ecdsa) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ecdsa) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ed25519) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ed25519) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ristretto255) (pull_request) Has been cancelled
Rust CI / no-std (wasm32-unknown-unknown / ristretto255) (pull_request) Has been cancelled
Rust CI / no-std (thumbv6m-none-eabi / ristretto255,curve25519,ecdsa,ed25519) (pull_request) Has been cancelled
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.88 - 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
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
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: 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.88.0"
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
||||
- uses: dtolnay/rust-toolchain@${{ matrix.toolchain }}
|
||||
- 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
|
||||
@@ -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
@@ -1,67 +1,112 @@
|
||||
# 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.88**
|
||||
* 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)
|
||||
|
||||
* Upgraded ml-kem from 0.2 to 0.3.0-rc.0
|
||||
* Increased MSRV to 1.87
|
||||
|
||||
## 4.1.0-pre.1 (November 17, 2025)
|
||||
|
||||
* Added ml-kem re-export behind the kem feature
|
||||
|
||||
## 4.1.0-pre.0 (November 11, 2025)
|
||||
|
||||
* Fixed dependency exporting for the rand crate
|
||||
* Added TripleDhKem key exchange protocol
|
||||
|
||||
## 4.0.1 (October 30, 2025)
|
||||
|
||||
* Fixing docs building issue
|
||||
|
||||
## 4.0.0 (October 23, 2025)
|
||||
|
||||
* Increased MSRV to 1.83
|
||||
* Synced implementation with RFC 9807 (no core protocol changes)
|
||||
* Added a SIGMA-I key exchange implementation
|
||||
* 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
|
||||
* Modified the dummy registration file to only contain the public key
|
||||
instead of the keypair
|
||||
* **Breaking: existing `ServerSetup`s need to be updated**
|
||||
```rust
|
||||
// Given `old` is a `ServerSetup` from `opaque-ke` v3.
|
||||
let old_serialized = old.serialize();
|
||||
|
||||
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;
|
||||
|
||||
let (old_serialied_rest, old_fake_keypair_serialized): (
|
||||
GenericArray<u8, Sum<OldSeedLen, OldSkLen>>,
|
||||
_,
|
||||
) = old_serialized.split();
|
||||
|
||||
let old_fake_keypair =
|
||||
KeyPair::<<OldCipherSuite as opaque_ke_3::CipherSuite>::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);
|
||||
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to `OldCipherSuite`.
|
||||
ServerSetup::<NewCipherSuite>::deserialize(&new_serialized).unwrap()
|
||||
```
|
||||
* **Breaking: existing `ServerSetup`s need to be updated**
|
||||
```rust
|
||||
// Given `old` is a `ServerSetup` from `opaque-ke` v3.
|
||||
let old_serialized = old.serialize();
|
||||
|
||||
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;
|
||||
|
||||
let (old_serialied_rest, old_fake_keypair_serialized): (
|
||||
GenericArray<u8, Sum<OldSeedLen, OldSkLen>>,
|
||||
_,
|
||||
) = old_serialized.split();
|
||||
|
||||
let old_fake_keypair =
|
||||
KeyPair::<<OldCipherSuite as opaque_ke_3::CipherSuite>::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);
|
||||
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to `OldCipherSuite`.
|
||||
ServerSetup::<NewCipherSuite>::deserialize(&new_serialized).unwrap()
|
||||
```
|
||||
* Added remote OPRF seed support
|
||||
* Replace remote private key trait with a state machine, facilitating async support.
|
||||
* Serde de/serialization formats have been simplified
|
||||
* **Breaking: existing `ServerRegistration`s may need to be updated**
|
||||
```rust
|
||||
// Given `old` is a `ServerRegistration` from `opaque-ke` v3.
|
||||
let old_serialized = old.serialize();
|
||||
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to the old cipher suite.
|
||||
ServerRegistration::<NewCipherSuite>::deserialize(&old_serialized).unwrap()
|
||||
```
|
||||
|
||||
* **Breaking: existing `ServerRegistration`s may need to be updated**
|
||||
```rust
|
||||
// Given `old` is a `ServerRegistration` from `opaque-ke` v3.
|
||||
let old_serialized = old.serialize();
|
||||
// Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to the old cipher suite.
|
||||
ServerRegistration::<NewCipherSuite>::deserialize(&old_serialized).unwrap()
|
||||
```
|
||||
|
||||
## 3.0.0 (October 10, 2024)
|
||||
|
||||
* 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
|
||||
* Updated dependencies
|
||||
* Increased MSRV to 1.74
|
||||
@@ -69,11 +114,12 @@
|
||||
* Adjusted key generation logic to be in line with commit 727b9ac of
|
||||
https://github.com/cfrg/draft-irtf-cfrg-opaque
|
||||
* 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
|
||||
* Renaming of X25519 to Curve25519
|
||||
|
||||
## 2.0.0 (September 21, 2022)
|
||||
|
||||
* Synced implementation with draft-irtf-cfrg-opaque-10
|
||||
* Changed argon2 salt length to recommended value (16 bytes)
|
||||
* Fixed issue from 2.0.0-pre.2 not pinning voprf dependency correctly
|
||||
|
||||
@@ -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
|
||||
@@ -2,29 +2,10 @@
|
||||
We want to make contributing to this project as easy and transparent as
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
+74
-65
@@ -1,110 +1,119 @@
|
||||
[package]
|
||||
authors = ["Kevin Lewi <[email protected]>", "François Garillot <[email protected]>"]
|
||||
categories = ["no-std"]
|
||||
authors = [
|
||||
"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"
|
||||
edition = "2024"
|
||||
exclude = ["/src/tests/"]
|
||||
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
|
||||
keywords = ["cryptography", "opaque", "passwords", "authentication", "pake"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
name = "opaque-ke"
|
||||
name = "opaque-vx"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/facebook/opaque-ke"
|
||||
rust-version = "1.87"
|
||||
version = "4.1.0-pre.2"
|
||||
repository = "https://github.com/vexahub/opaque-vx"
|
||||
rust-version = "1.88"
|
||||
version = "1.0.0-pre.0"
|
||||
|
||||
[features]
|
||||
argon2 = ["dep:argon2"]
|
||||
curve25519 = ["dep:curve25519-dalek"]
|
||||
default = ["ristretto255", "serde"]
|
||||
ecdsa = ["dep:ecdsa", "dep:rfc6979"]
|
||||
ecdsa = ["dep:ecdsa"]
|
||||
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"]
|
||||
serde = [
|
||||
"dep:serde",
|
||||
"curve25519-dalek?/serde",
|
||||
"ecdsa?/serde",
|
||||
"ed25519-dalek?/serde",
|
||||
"elliptic-curve/serde",
|
||||
"generic-array/serde",
|
||||
"voprf/serde",
|
||||
"zeroize/serde",
|
||||
"dep:serde",
|
||||
"curve25519-dalek?/serde",
|
||||
"ecdsa?/serde",
|
||||
"ed25519-dalek?/serde",
|
||||
"elliptic-curve/serde",
|
||||
"generic-array/serde",
|
||||
"hybrid-array/serde",
|
||||
"voprf/serde",
|
||||
"zeroize/serde",
|
||||
]
|
||||
std = ["dep:getrandom", "rand/std"]
|
||||
|
||||
[dependencies]
|
||||
argon2 = { version = "0.5", default-features = false, features = [
|
||||
"alloc",
|
||||
argon2 = { version = "0.6.0-rc", default-features = false, features = [
|
||||
"alloc",
|
||||
], optional = true }
|
||||
curve25519-dalek = { version = "4", default-features = false, features = [
|
||||
"zeroize",
|
||||
curve25519-dalek = { version = "5.0.0-rc", default-features = false, features = [
|
||||
"zeroize",
|
||||
], optional = true }
|
||||
derive-where = { version = "1.4", features = ["zeroize-on-drop"] }
|
||||
digest = "0.10"
|
||||
derive-where = { version = "1.6", features = ["zeroize-on-drop"] }
|
||||
digest = { version = "0.11", features = ["zeroize"] }
|
||||
displaydoc = { version = "0.2", default-features = false }
|
||||
ecdsa = { version = "0.16", default-features = false, features = [
|
||||
"arithmetic",
|
||||
"hazmat",
|
||||
ecdsa = { version = "0.17.0-rc.23", default-features = false, features = [
|
||||
"algorithm",
|
||||
], optional = true }
|
||||
ed25519-dalek = { version = "2", default-features = false, features = [
|
||||
"digest",
|
||||
"hazmat",
|
||||
ed25519-dalek = { version = "3.0.0-rc", default-features = false, features = [
|
||||
"digest",
|
||||
"hazmat",
|
||||
], optional = true }
|
||||
elliptic-curve = { version = "0.13", features = ["hash2curve", "sec1"] }
|
||||
generic-array = "=0.14.7" # pinned to avoid deprecation warnings
|
||||
hkdf = "0.12"
|
||||
hmac = "0.12"
|
||||
ml-kem = { version = "0.3.0-rc.0", default-features = false, features = [
|
||||
"zeroize",
|
||||
elliptic-curve = { version = "0.14", features = ["sec1"] }
|
||||
generic-array = { version = "1.4", features = ["hybrid-array-0_4", "zeroize"] }
|
||||
hybrid-array = { version = "0.4", features = ["extra-sizes", "zeroize"] }
|
||||
hkdf = "0.13"
|
||||
hmac = "0.13"
|
||||
ml-kem = { version = "0.3", default-features = false, features = [
|
||||
"zeroize",
|
||||
], optional = true }
|
||||
rand = { version = "0.8", default-features = false }
|
||||
rand_core_10 = { package = "rand_core", version = "0.10", default-features = false, optional = true }
|
||||
rfc6979 = { version = "0.4", optional = true }
|
||||
rand = { version = "0.10", default-features = false }
|
||||
rand_core = { version = "0.10", default-features = false, optional = true }
|
||||
serde = { version = "1", default-features = false, features = [
|
||||
"derive",
|
||||
"derive",
|
||||
], optional = true }
|
||||
subtle = { version = "2.6", default-features = false }
|
||||
voprf = { version = "0.5", default-features = false, features = ["danger"] }
|
||||
zeroize = { version = "1.8", features = ["zeroize_derive"] }
|
||||
voprf = {
|
||||
package = "voprf-vx",
|
||||
version = "1.0.0-pre.0",
|
||||
default-features = false,
|
||||
features = ["danger"]
|
||||
}
|
||||
zeroize = { version = "1.9", features = ["zeroize_derive"] }
|
||||
|
||||
[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]
|
||||
anyhow = "1"
|
||||
bincode = "1"
|
||||
chacha20poly1305 = "0.10"
|
||||
postcard = { version = "1", features = ["alloc"] }
|
||||
chacha20poly1305 = "0.11"
|
||||
criterion = "0.8"
|
||||
cryptoki = "0.9"
|
||||
elliptic-curve = { version = "0.13", features = ["alloc", "pkcs8"] }
|
||||
cryptoki = "0.12"
|
||||
elliptic-curve = { version = "0.14", features = ["alloc", "pkcs8"] }
|
||||
rand_core = { version = "0.10", default-features = false }
|
||||
hex = "0.4"
|
||||
opaque-ke-3 = { package = "opaque-ke", version = "=3.0.0" }
|
||||
p256 = { version = "0.13", default-features = false, features = [
|
||||
"ecdsa",
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"voprf",
|
||||
p256 = { version = "0.14.0-rc.15", default-features = false, features = [
|
||||
"ecdsa",
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"oprf",
|
||||
] }
|
||||
p384 = { version = "0.13", default-features = false, features = [
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"voprf",
|
||||
p384 = { version = "0.14.0-rc.15", default-features = false, features = [
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"oprf",
|
||||
] }
|
||||
p521 = { version = "0.13.3", default-features = false, features = [
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"voprf",
|
||||
p521 = { version = "0.14.0-rc.15", default-features = false, features = [
|
||||
"hash2curve",
|
||||
"pkcs8",
|
||||
"oprf",
|
||||
] }
|
||||
paste = "1"
|
||||
proptest = "1"
|
||||
rand = "0.8"
|
||||
rand_chacha = "0.3"
|
||||
rand = "0.10"
|
||||
rand_chacha = "0.10"
|
||||
regex = "1"
|
||||
sha2 = { version = "0.10", default-features = false }
|
||||
sha2 = { version = "0.11", default-features = false }
|
||||
thiserror = "2"
|
||||
# MSRV
|
||||
rustyline = "17"
|
||||
scrypt = "0.11"
|
||||
rustyline = "18"
|
||||
scrypt = "0.12"
|
||||
serde_json = "1"
|
||||
|
||||
[[bench]]
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
## The OPAQUE key exchange protocol 
|
||||
## 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 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
|
||||
----------
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
------------
|
||||
@@ -22,41 +30,52 @@ Installation
|
||||
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
|
||||
|
||||
Rust **1.87** or higher.
|
||||
Rust **1.88** or higher.
|
||||
|
||||
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
|
||||
---------
|
||||
|
||||
- [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
|
||||
- ["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
|
||||
- [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)
|
||||
- [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`
|
||||
- [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)
|
||||
- [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
|
||||
------------
|
||||
|
||||
The authors of this code are Kevin Lewi
|
||||
([@kevinlewi](https://github.com/kevinlewi)) and François Garillot ([@huitseeker](https://github.com/huitseeker)).
|
||||
This fork is maintained by [VexaHub](https://github.com/vexahub).
|
||||
|
||||
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).
|
||||
|
||||
#### Acknowledgments
|
||||
|
||||
Special thanks go to Hugo Krawczyk and Chris Wood for helping to clarify discrepancies and making suggestions for improving
|
||||
this implementation. Additional credit goes to @daxpedda for adding no_std support, p256 support, and making other general
|
||||
Special thanks go to Hugo Krawczyk and Chris Wood for helping to clarify discrepancies and making suggestions for
|
||||
improving
|
||||
this implementation. Additional credit goes to @daxpedda for adding no_std support, p256 support, and making other
|
||||
general
|
||||
improvements to the library.
|
||||
|
||||
License
|
||||
|
||||
+18
-17
@@ -10,8 +10,9 @@
|
||||
extern crate criterion;
|
||||
|
||||
use criterion::Criterion;
|
||||
use opaque_ke::*;
|
||||
use rand::rngs::OsRng;
|
||||
use opaque_vx::*;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_core::UnwrapErr;
|
||||
|
||||
#[cfg(feature = "ristretto255")]
|
||||
static SUFFIX: &str = "ristretto255";
|
||||
@@ -22,20 +23,20 @@ struct Default;
|
||||
|
||||
#[cfg(feature = "ristretto255")]
|
||||
impl CipherSuite for Default {
|
||||
type OprfCs = opaque_ke::Ristretto255;
|
||||
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
type Ksf = opaque_ke::ksf::Identity;
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ristretto255"))]
|
||||
impl CipherSuite for Default {
|
||||
type OprfCs = p256::NistP256;
|
||||
type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = opaque_ke::ksf::Identity;
|
||||
type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
fn server_setup(c: &mut Criterion) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
|
||||
c.bench_function(&format!("server setup ({SUFFIX})"), move |b| {
|
||||
b.iter(|| {
|
||||
@@ -45,7 +46,7 @@ fn server_setup(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
fn client_registration_start(c: &mut Criterion) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let password = b"password";
|
||||
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let password = b"password";
|
||||
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
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) {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let username = b"username";
|
||||
let password = b"password";
|
||||
let server_setup = ServerSetup::<Default>::new(&mut rng);
|
||||
|
||||
+23
-23
@@ -30,16 +30,16 @@ use std::process::exit;
|
||||
|
||||
use chacha20poly1305::aead::{Aead, KeyInit};
|
||||
use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce};
|
||||
use opaque_ke::ciphersuite::CipherSuite;
|
||||
use opaque_ke::generic_array::GenericArray;
|
||||
use opaque_ke::rand::RngCore;
|
||||
use opaque_ke::rand::rngs::OsRng;
|
||||
use opaque_ke::{
|
||||
use opaque_vx::ciphersuite::CipherSuite;
|
||||
use opaque_vx::rand::Rng;
|
||||
use opaque_vx::rand::rngs::SysRng;
|
||||
use opaque_vx::{
|
||||
ClientLogin, ClientLoginFinishParameters, ClientRegistration,
|
||||
ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest,
|
||||
CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin,
|
||||
ServerLoginParameters, ServerRegistration, ServerRegistrationLen, ServerSetup,
|
||||
ServerLoginParameters, ServerRegistration, ServerSetup,
|
||||
};
|
||||
use rand_core::UnwrapErr;
|
||||
use rustyline::Editor;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::history::DefaultHistory;
|
||||
@@ -51,43 +51,43 @@ struct DefaultCipherSuite;
|
||||
|
||||
#[cfg(feature = "ristretto255")]
|
||||
impl CipherSuite for DefaultCipherSuite {
|
||||
type OprfCs = opaque_ke::Ristretto255;
|
||||
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
type Ksf = opaque_ke::ksf::Identity;
|
||||
type OprfCs = opaque_vx::Ristretto255;
|
||||
type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
type Ksf = opaque_vx::ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ristretto255"))]
|
||||
impl CipherSuite for DefaultCipherSuite {
|
||||
type OprfCs = p256::NistP256;
|
||||
type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = opaque_ke::ksf::Identity;
|
||||
type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = opaque_vx::ksf::Identity;
|
||||
}
|
||||
|
||||
struct Locker {
|
||||
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
|
||||
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];
|
||||
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()
|
||||
}
|
||||
|
||||
// Decrypt using a key and a ciphertext (nonce included) to recover the original
|
||||
// plaintext
|
||||
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
|
||||
.decrypt(
|
||||
Nonce::from_slice(&ciphertext[..12]),
|
||||
&Nonce::try_from(&ciphertext[..12]).unwrap(),
|
||||
ciphertext[12..].as_ref(),
|
||||
)
|
||||
.unwrap()
|
||||
@@ -101,7 +101,7 @@ fn register_locker(
|
||||
password: String,
|
||||
secret_message: String,
|
||||
) -> Locker {
|
||||
let mut client_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
|
||||
.unwrap();
|
||||
@@ -143,7 +143,7 @@ fn register_locker(
|
||||
|
||||
Locker {
|
||||
contents: ciphertext,
|
||||
password_file: password_file.serialize(),
|
||||
password_file: password_file.serialize().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ fn open_locker(
|
||||
password: String,
|
||||
locker: &Locker,
|
||||
) -> Result<String, String> {
|
||||
let mut client_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let client_login_start_result =
|
||||
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
|
||||
let credential_request_bytes = client_login_start_result.message.serialize();
|
||||
@@ -163,7 +163,7 @@ fn open_locker(
|
||||
|
||||
let password_file =
|
||||
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(
|
||||
&mut server_rng,
|
||||
server_setup,
|
||||
@@ -217,7 +217,7 @@ fn open_locker(
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
|
||||
|
||||
let mut rl = Editor::<(), _>::new().unwrap();
|
||||
|
||||
+18
-18
@@ -22,22 +22,22 @@
|
||||
//! over "the wire" to the server. These bytes are serialized and explicitly
|
||||
//! annotated in the below functions.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::process::exit;
|
||||
|
||||
use opaque_ke::argon2::Argon2;
|
||||
use opaque_ke::ciphersuite::CipherSuite;
|
||||
use opaque_ke::generic_array::GenericArray;
|
||||
use opaque_ke::rand::rngs::OsRng;
|
||||
use opaque_ke::{
|
||||
use opaque_vx::argon2::Argon2;
|
||||
use opaque_vx::ciphersuite::CipherSuite;
|
||||
use opaque_vx::hybrid_array::Array;
|
||||
use opaque_vx::rand::rngs::SysRng;
|
||||
use opaque_vx::{
|
||||
ClientLogin, ClientLoginFinishParameters, ClientRegistration,
|
||||
ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest,
|
||||
CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload, ServerLogin,
|
||||
ServerLoginParameters, ServerRegistration, ServerRegistrationLen, ServerSetup,
|
||||
};
|
||||
use rand_core::UnwrapErr;
|
||||
use rustyline::Editor;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::history::DefaultHistory;
|
||||
use std::collections::HashMap;
|
||||
use std::process::exit;
|
||||
|
||||
// The ciphersuite trait allows to specify the underlying primitives that will
|
||||
// be used in the OPAQUE protocol
|
||||
@@ -46,8 +46,8 @@ struct DefaultCipherSuite;
|
||||
|
||||
#[cfg(feature = "ristretto255")]
|
||||
impl CipherSuite for DefaultCipherSuite {
|
||||
type OprfCs = opaque_ke::Ristretto255;
|
||||
type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
type OprfCs = opaque_vx::Ristretto255;
|
||||
type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
|
||||
type Ksf = Argon2<'static>;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ impl CipherSuite for DefaultCipherSuite {
|
||||
#[cfg(not(feature = "ristretto255"))]
|
||||
impl CipherSuite for DefaultCipherSuite {
|
||||
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>;
|
||||
}
|
||||
@@ -65,8 +65,8 @@ fn account_registration(
|
||||
server_setup: &ServerSetup<DefaultCipherSuite>,
|
||||
username: String,
|
||||
password: String,
|
||||
) -> GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>> {
|
||||
let mut client_rng = OsRng;
|
||||
) -> Array<u8, ServerRegistrationLen<DefaultCipherSuite>> {
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
|
||||
.unwrap();
|
||||
@@ -100,7 +100,7 @@ fn account_registration(
|
||||
let password_file = ServerRegistration::finish(
|
||||
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
|
||||
);
|
||||
password_file.serialize()
|
||||
password_file.serialize().into_ha0_4()
|
||||
}
|
||||
|
||||
// Password-based login between a client and server
|
||||
@@ -110,7 +110,7 @@ fn account_login(
|
||||
password: String,
|
||||
password_file_bytes: &[u8],
|
||||
) -> bool {
|
||||
let mut client_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let client_login_start_result =
|
||||
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
|
||||
let credential_request_bytes = client_login_start_result.message.serialize();
|
||||
@@ -119,7 +119,7 @@ fn account_login(
|
||||
|
||||
let password_file =
|
||||
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(
|
||||
&mut server_rng,
|
||||
server_setup,
|
||||
@@ -161,12 +161,12 @@ fn account_login(
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
|
||||
|
||||
let mut rl = Editor::<(), _>::new().unwrap();
|
||||
let mut registered_users =
|
||||
HashMap::<String, GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new();
|
||||
HashMap::<String, Array<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new();
|
||||
loop {
|
||||
println!(
|
||||
"\nCurrently registered usernames: {:?}\n",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
unstable_features = true
|
||||
wrap_comments = true
|
||||
|
||||
+10
-8
@@ -11,7 +11,7 @@
|
||||
|
||||
use core::ops::Add;
|
||||
|
||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||
use digest::block_api::{CoreProxy, EagerHash, SmallBlockSizeUser};
|
||||
use generic_array::ArrayLength;
|
||||
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
|
||||
pub trait CipherSuite
|
||||
where
|
||||
OprfHash<Self>: Hash,
|
||||
OprfHash<Self>: Hash + EagerHash,
|
||||
<OprfHash<Self> as CoreProxy>::Core: ProxyHash,
|
||||
<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<<OprfHash<Self> as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<OprfHash<Self> as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
// Envelope: Nonce + Hash
|
||||
// MaskedResponse: (Nonce + Hash) + KePk
|
||||
OutputSize<OprfHash<Self>>: Add<NonceLen>,
|
||||
Sum<OutputSize<OprfHash<Self>>, NonceLen>:
|
||||
ArrayLength<u8> + Add<<KeGroup<Self> as Group>::PkLen>,
|
||||
MaskedResponseLen<Self>: ArrayLength<u8>,
|
||||
OutputSize<OprfHash<Self>>: Add<NonceLen> + ArrayLength,
|
||||
Sum<OutputSize<OprfHash<Self>>, NonceLen>: ArrayLength + Add<<KeGroup<Self> as Group>::PkLen>,
|
||||
MaskedResponseLen<Self>: ArrayLength,
|
||||
// hybrid-array interop bounds
|
||||
<OprfGroup<Self> as voprf::Group>::ScalarLen: ArrayLength,
|
||||
<OprfGroup<Self> as voprf::Group>::ElemLen: ArrayLength,
|
||||
{
|
||||
/// A VOPRF ciphersuite, see [`voprf::CipherSuite`].
|
||||
type OprfCs: voprf::CipherSuite;
|
||||
|
||||
+32
-23
@@ -11,11 +11,10 @@ use core::convert::TryFrom;
|
||||
use derive_where::derive_where;
|
||||
use digest::Output;
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{Sum, U32};
|
||||
use hkdf::Hkdf;
|
||||
use hmac::{Hmac, Mac};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hkdf::SimpleHkdf as Hkdf;
|
||||
use hmac::{KeyInit, Mac, SimpleHmac};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::ciphersuite::{CipherSuite, KeGroup, OprfHash};
|
||||
@@ -25,7 +24,7 @@ use crate::key_exchange::SerializedIdentifiers;
|
||||
use crate::key_exchange::group::Group;
|
||||
use crate::keypair::{KeyPair, PrivateKey, PublicKey};
|
||||
use crate::opaque::Identifiers;
|
||||
use crate::serialization::{GenericArrayExt, SliceExt, UpdateExt};
|
||||
use crate::serialization::{SliceExt, UpdateExt};
|
||||
|
||||
// Constant string used as salt for HKDF computation
|
||||
const STR_AUTH_KEY: [u8; 7] = *b"AuthKey";
|
||||
@@ -108,9 +107,9 @@ pub(crate) type EnvelopeLen<CS: CipherSuite> = Sum<OutputSize<OprfHash<CS>>, Non
|
||||
|
||||
impl<CS: CipherSuite> Envelope<CS> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn seal<R: RngCore + CryptoRng>(
|
||||
pub(crate) fn seal<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
|
||||
server_s_pk: &PublicKey<KeGroup<CS>>,
|
||||
ids: Identifiers,
|
||||
) -> Result<SealResult<CS>, ProtocolError> {
|
||||
@@ -119,7 +118,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
|
||||
let (mode, client_s_pk) = (
|
||||
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();
|
||||
@@ -148,7 +147,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
/// the aad field. Note that a new nonce is sampled for each call to seal.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn seal_raw<'a>(
|
||||
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
|
||||
nonce: GenericArray<u8, NonceLen>,
|
||||
aad: impl Iterator<Item = &'a [u8]>,
|
||||
mode: InnerEnvelopeMode,
|
||||
@@ -163,7 +162,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
.expand_multi_info(&[&nonce, &STR_EXPORT_KEY], &mut export_key)
|
||||
.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)?;
|
||||
hmac.update(&nonce);
|
||||
hmac.update_iter(aad);
|
||||
@@ -184,7 +183,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
|
||||
pub(crate) fn open<'a>(
|
||||
&self,
|
||||
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
|
||||
server_s_pk: PublicKey<KeGroup<CS>>,
|
||||
optional_ids: Identifiers<'a>,
|
||||
) -> Result<OpenedEnvelope<'a, CS>, ProtocolError> {
|
||||
@@ -193,7 +192,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
return Err(InternalError::IncompatibleEnvelopeModeError.into());
|
||||
}
|
||||
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.
|
||||
pub(crate) fn open_raw<'a>(
|
||||
&self,
|
||||
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
|
||||
aad: impl Iterator<Item = &'a [u8]>,
|
||||
) -> Result<OpenedInnerEnvelope<CS>, InternalError> {
|
||||
let mut hmac_key = Output::<OprfHash<CS>>::default();
|
||||
let mut export_key = Output::<OprfHash<CS>>::default();
|
||||
|
||||
randomized_pwd_hasher
|
||||
.expand(&self.nonce.concat(STR_AUTH_KEY.into()), &mut hmac_key)
|
||||
.expand_multi_info(&[&self.nonce, &STR_AUTH_KEY], &mut hmac_key)
|
||||
.map_err(|_| InternalError::HkdfError)?;
|
||||
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)?;
|
||||
|
||||
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)?;
|
||||
hmac.update(&self.nonce);
|
||||
hmac.update_iter(aad);
|
||||
@@ -250,7 +249,7 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
Self {
|
||||
mode: InnerEnvelopeMode::Zero,
|
||||
nonce: GenericArray::default(),
|
||||
hmac: GenericArray::default(),
|
||||
hmac: GenericArray::default().into_ha0_4(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,15 +260,25 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
OutputSize::<OprfHash<CS>>::USIZE + NonceLen::USIZE
|
||||
}
|
||||
|
||||
// TODO: check if ok
|
||||
pub(crate) fn serialize(&self) -> GenericArray<u8, EnvelopeLen<CS>> {
|
||||
self.nonce.concat_ext(&self.hmac)
|
||||
use generic_array::typenum::Unsigned;
|
||||
|
||||
let mut buf = GenericArray::<u8, EnvelopeLen<CS>>::default();
|
||||
|
||||
buf[..NonceLen::USIZE].copy_from_slice(&self.nonce);
|
||||
buf[NonceLen::USIZE..].copy_from_slice(&self.hmac);
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
mode: InnerEnvelopeMode::Internal,
|
||||
nonce: bytes.take_array("nonce")?,
|
||||
hmac: bytes.take_array("hmac")?,
|
||||
hmac: bytes
|
||||
.take_array::<OutputSize<OprfHash<CS>>>("hmac")?
|
||||
.into_ha0_4(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -277,12 +286,12 @@ impl<CS: CipherSuite> Envelope<CS> {
|
||||
// Helper functions
|
||||
|
||||
fn build_inner_envelope_internal<CS: CipherSuite>(
|
||||
randomized_pwd_hasher: Hkdf<OprfHash<CS>>,
|
||||
randomized_pwd_hasher: &Hkdf<OprfHash<CS>>,
|
||||
nonce: GenericArray<u8, NonceLen>,
|
||||
) -> Result<PublicKey<KeGroup<CS>>, ProtocolError> {
|
||||
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
|
||||
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)?;
|
||||
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
|
||||
|
||||
@@ -290,12 +299,12 @@ fn build_inner_envelope_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>,
|
||||
) -> Result<KeyPair<KeGroup<CS>>, ProtocolError> {
|
||||
let mut keypair_seed = GenericArray::<_, <KeGroup<CS> as Group>::SkLen>::default();
|
||||
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)?;
|
||||
let client_s_sk = PrivateKey::new(KeGroup::<CS>::derive_scalar(keypair_seed)?);
|
||||
let client_s_pk = client_s_sk.public_key();
|
||||
|
||||
+3
-2
@@ -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,
|
||||
// and https://github.com/dtolnay/thiserror/issues/62 for why this comes up in our
|
||||
// doc tests.
|
||||
impl<T> From<::core::convert::Infallible> for ProtocolError<T> {
|
||||
fn from(_: ::core::convert::Infallible) -> Self {
|
||||
impl<T> From<Infallible> for ProtocolError<T> {
|
||||
fn from(_: Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,7 @@ impl ProtocolError {
|
||||
actual_len,
|
||||
},
|
||||
Self::ReflectedValueError => ProtocolError::ReflectedValueError,
|
||||
Self::Custom(infallible) => match infallible {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-15
@@ -8,36 +8,45 @@
|
||||
|
||||
//! 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::core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore};
|
||||
use digest::{FixedOutputReset, HashMarker, OutputSizeUser};
|
||||
use digest::{Digest, FixedOutputReset, HashMarker, OutputSizeUser};
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, U256};
|
||||
|
||||
pub(crate) type OutputSize<H> = <<H as CoreProxy>::Core as OutputSizeUser>::OutputSize;
|
||||
|
||||
/// Trait to simplify requirements for [`Hash`].
|
||||
pub trait ProxyHash:
|
||||
HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone
|
||||
HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + OutputSizeUser + Default + Clone
|
||||
where
|
||||
<Self as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<Self as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<Self as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: HashMarker + FixedOutputCore + BufferKindUser<BufferKind = Eager> + Default + Clone>
|
||||
ProxyHash for T
|
||||
impl<
|
||||
T: HashMarker
|
||||
+ FixedOutputCore
|
||||
+ BufferKindUser<BufferKind = Eager>
|
||||
+ OutputSizeUser
|
||||
+ Default
|
||||
+ Clone,
|
||||
> ProxyHash for T
|
||||
where
|
||||
<Self as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<Self as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<T as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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
|
||||
/// as defaults: <https://github.com/rust-lang/rust/issues/29661>
|
||||
pub trait Hash:
|
||||
Default
|
||||
+ HashMarker
|
||||
+ Digest
|
||||
+ OutputSizeUser<OutputSize = OutputSize<Self>>
|
||||
+ BlockSizeUser
|
||||
+ FixedOutputReset
|
||||
@@ -45,14 +54,16 @@ pub trait Hash:
|
||||
+ Clone
|
||||
where
|
||||
<Self as CoreProxy>::Core: ProxyHash,
|
||||
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<Self as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<Self>: generic_array::ArrayLength,
|
||||
{
|
||||
}
|
||||
|
||||
impl<
|
||||
T: Default
|
||||
+ HashMarker
|
||||
+ Digest
|
||||
+ OutputSizeUser<OutputSize = OutputSize<Self>>
|
||||
+ BlockSizeUser
|
||||
+ FixedOutputReset
|
||||
@@ -60,8 +71,9 @@ impl<
|
||||
+ Clone,
|
||||
> Hash for T
|
||||
where
|
||||
<Self as CoreProxy>::Core: ProxyHash,
|
||||
<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<<Self as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<T as CoreProxy>::Core: ProxyHash,
|
||||
<<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<T as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<T>: generic_array::ArrayLength,
|
||||
{
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use curve25519_dalek::scalar;
|
||||
use curve25519_dalek::traits::IsIdentity;
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::U32;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use subtle::ConstantTimeEq;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
@@ -43,7 +43,7 @@ impl Group for Curve25519 {
|
||||
.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
|
||||
let mut scalar_bytes = [0u8; 32];
|
||||
rng.fill_bytes(&mut scalar_bytes);
|
||||
|
||||
@@ -18,9 +18,8 @@ pub use ed25519_dalek;
|
||||
use ed25519_dalek::hazmat::ExpandedSecretKey;
|
||||
use ed25519_dalek::{SecretKey, Sha512};
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{U32, U64};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
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;
|
||||
pub use crate::key_exchange::sigma_i::shared::PreHash;
|
||||
use crate::key_exchange::sigma_i::{CachedMessage, Message, MessageBuilder};
|
||||
use crate::serialization::{SliceExt, UpdateExt};
|
||||
use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
|
||||
|
||||
/// Implementation for Ed25519.
|
||||
pub struct Ed25519;
|
||||
@@ -46,12 +45,12 @@ impl Group for Ed25519 {
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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();
|
||||
rng.fill_bytes(&mut sk);
|
||||
|
||||
@@ -72,7 +71,7 @@ impl Group for Ed25519 {
|
||||
|
||||
fn deserialize_take_sk(bytes: &mut &[u8]) -> Result<Self::Sk, ProtocolError> {
|
||||
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 {
|
||||
/// 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.
|
||||
pub fn from_slice(mut bytes: &[u8]) -> Result<Self, ProtocolError> {
|
||||
Self::deserialize_take(&mut bytes)
|
||||
@@ -407,9 +406,9 @@ impl Signature {
|
||||
|
||||
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
#[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()
|
||||
.ok_or(ProtocolError::SerializationError)?;
|
||||
|
||||
@@ -417,7 +416,8 @@ impl Signature {
|
||||
}
|
||||
|
||||
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 ed25519_dalek::{Signer, SigningKey, Verifier, VerifyingKey};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_core::UnwrapErr;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn pure_eddsa() {
|
||||
let mut message = [0; 1024];
|
||||
OsRng.fill_bytes(&mut message);
|
||||
UnwrapErr(SysRng).fill_bytes(&mut message);
|
||||
|
||||
let mut sk = SecretKey::default();
|
||||
OsRng.fill_bytes(&mut sk);
|
||||
UnwrapErr(SysRng).fill_bytes(&mut sk);
|
||||
let signing_key = SigningKey::from_bytes(&sk);
|
||||
|
||||
let signature = signing_key.sign(&message);
|
||||
@@ -472,12 +473,12 @@ mod test {
|
||||
#[test]
|
||||
fn hash_eddsa() {
|
||||
let mut message = [0; 1024];
|
||||
OsRng.fill_bytes(&mut message);
|
||||
UnwrapErr(SysRng).fill_bytes(&mut message);
|
||||
let message = Sha512::new_with_prefix(message);
|
||||
let pre_hash = message.clone().finalize();
|
||||
|
||||
let mut sk = SecretKey::default();
|
||||
OsRng.fill_bytes(&mut sk);
|
||||
UnwrapErr(SysRng).fill_bytes(&mut sk);
|
||||
let signing_key = SigningKey::from_bytes(&sk);
|
||||
|
||||
let signature = signing_key.sign_prehashed(message.clone(), None).unwrap();
|
||||
|
||||
@@ -8,17 +8,18 @@
|
||||
|
||||
//! Implementation for EC curves via [`elliptic_curve`] traits.
|
||||
|
||||
use core::fmt::{self, Debug, Formatter};
|
||||
|
||||
use derive_where::derive_where;
|
||||
use core::ops::Mul;
|
||||
use digest::OutputSizeUser;
|
||||
use digest::block_api::BlockSizeUser;
|
||||
use elliptic_curve::group::GroupEncoding;
|
||||
use elliptic_curve::ops::MulByGenerator;
|
||||
use elliptic_curve::sec1::{ModulusSize, ToEncodedPoint};
|
||||
use elliptic_curve::point::NonIdentity;
|
||||
use elliptic_curve::sec1::{ModulusSize, ToSec1Point};
|
||||
use elliptic_curve::{
|
||||
CurveArithmetic, FieldBytesSize, NonZeroScalar, ProjectivePoint, Scalar, SecretKey, point,
|
||||
CurveArithmetic, FieldBytesSize, Generate, NonZeroScalar, ProjectivePoint, Scalar, SecretKey,
|
||||
};
|
||||
use generic_array::GenericArray;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U256};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use voprf::Mode;
|
||||
|
||||
use super::{Group, STR_OPAQUE_DERIVE_AUTH_KEY_PAIR};
|
||||
@@ -29,15 +30,27 @@ use crate::serialization::SliceExt;
|
||||
impl<G> Group for G
|
||||
where
|
||||
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<
|
||||
Repr = GenericArray<u8, <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize>,
|
||||
> + ToEncodedPoint<Self>,
|
||||
Repr = hybrid_array::Array<
|
||||
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
|
||||
// format ideal for serialization and not computation. This is inconsistent with
|
||||
// our other implementations.
|
||||
type Pk = NonIdentity<Self>;
|
||||
type Pk = NonIdentity<ProjectivePoint<Self>>;
|
||||
|
||||
type PkLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
|
||||
|
||||
@@ -46,18 +59,19 @@ where
|
||||
type SkLen = FieldBytesSize<Self>;
|
||||
|
||||
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> {
|
||||
point::NonIdentity::<ProjectivePoint<Self>>::from_bytes(&bytes.take_array("public key")?)
|
||||
.into_option()
|
||||
.map(NonIdentity)
|
||||
.ok_or(ProtocolError::SerializationError)
|
||||
NonIdentity::<ProjectivePoint<Self>>::from_bytes(
|
||||
&bytes.take_array("public key")?.into_ha0_4(),
|
||||
)
|
||||
.into_option()
|
||||
.ok_or(ProtocolError::SerializationError)
|
||||
}
|
||||
|
||||
fn random_sk<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Sk {
|
||||
SecretKey::<Self>::random(rng)
|
||||
fn random_sk<R: Rng + CryptoRng>(rng: &mut R) -> Self::Sk {
|
||||
SecretKey::<Self>::generate_from_rng(rng)
|
||||
}
|
||||
|
||||
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 {
|
||||
// Non-panicking version in https://github.com/RustCrypto/traits/pull/1833.
|
||||
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"),
|
||||
)
|
||||
NonIdentity::<ProjectivePoint<Self>>::mul_by_generator(&sk.to_nonzero_scalar())
|
||||
}
|
||||
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -92,51 +100,26 @@ where
|
||||
impl<G> DiffieHellman<G> for SecretKey<G>
|
||||
where
|
||||
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<
|
||||
Repr = GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>,
|
||||
> + ToEncodedPoint<G>,
|
||||
Repr = hybrid_array::Array<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize>,
|
||||
> + 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(
|
||||
&self,
|
||||
pk: &NonIdentity<G>,
|
||||
pk: &NonIdentity<ProjectivePoint<G>>,
|
||||
) -> GenericArray<u8, <FieldBytesSize<G> as ModulusSize>::CompressedPointSize> {
|
||||
GenericArray::clone_from_slice(
|
||||
(pk.0 * self.to_nonzero_scalar())
|
||||
.to_encoded_point(true)
|
||||
GenericArray::from_slice(
|
||||
(pk * self.to_nonzero_scalar())
|
||||
.to_sec1_point(true)
|
||||
.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> {}
|
||||
|
||||
@@ -17,7 +17,8 @@ pub mod elliptic_curve;
|
||||
pub mod ristretto255;
|
||||
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hybrid_array::ArraySize;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
use crate::errors::{InternalError, ProtocolError};
|
||||
@@ -29,11 +30,11 @@ pub trait Group {
|
||||
/// Public key
|
||||
type Pk: Clone;
|
||||
/// Length of the public key
|
||||
type PkLen: ArrayLength<u8>;
|
||||
type PkLen: ArrayLength + ArraySize;
|
||||
/// Secret key
|
||||
type Sk: Clone + ZeroizeOnDrop;
|
||||
/// Length of the secret key
|
||||
type SkLen: ArrayLength<u8>;
|
||||
type SkLen: ArrayLength + ArraySize;
|
||||
|
||||
/// Serializes `self`
|
||||
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>;
|
||||
|
||||
/// 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`.
|
||||
fn derive_scalar(seed: GenericArray<u8, Self::SkLen>) -> Result<Self::Sk, InternalError>;
|
||||
|
||||
@@ -13,11 +13,12 @@ use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
|
||||
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use curve25519_dalek::traits::IsIdentity;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::block_api::BlockSizeUser;
|
||||
use digest::{FixedOutput, HashMarker};
|
||||
use generic_array::GenericArray;
|
||||
use generic_array::typenum::{IsLess, IsLessOrEqual, U32, U256};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use generic_array::typenum::{IsGreaterOrEqual, IsLess, IsLessOrEqual, Prod, True, U2, U32, U256};
|
||||
use hybrid_array::Array;
|
||||
use rand::{CryptoRng, Rng, TryCryptoRng, TryRng};
|
||||
use voprf::Mode;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
@@ -42,15 +43,19 @@ impl Group for Ristretto255 {
|
||||
}
|
||||
|
||||
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()
|
||||
.ok_or(ProtocolError::SerializationError)
|
||||
.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 {
|
||||
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 {
|
||||
break NonZeroScalar(scalar);
|
||||
@@ -73,7 +78,7 @@ impl Group for Ristretto255 {
|
||||
}
|
||||
|
||||
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()
|
||||
.ok_or(ProtocolError::SerializationError)
|
||||
.and_then(NonZeroScalar::from_scalar)
|
||||
@@ -149,7 +154,7 @@ where
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -165,13 +170,17 @@ impl voprf::Group for Ristretto255 {
|
||||
|
||||
type ScalarLen = <voprf::Ristretto255 as voprf::Group>::ScalarLen;
|
||||
|
||||
type SecurityLevel = <voprf::Ristretto255 as voprf::Group>::SecurityLevel;
|
||||
|
||||
fn hash_to_curve<H>(
|
||||
input: &[&[u8]],
|
||||
dst: &[&[u8]],
|
||||
) -> voprf::Result<Self::Elem, voprf::InternalError>
|
||||
where
|
||||
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)
|
||||
}
|
||||
@@ -182,7 +191,9 @@ impl voprf::Group for Ristretto255 {
|
||||
) -> voprf::Result<Self::Scalar, voprf::InternalError>
|
||||
where
|
||||
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)
|
||||
}
|
||||
@@ -195,7 +206,7 @@ impl voprf::Group for Ristretto255 {
|
||||
<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)
|
||||
}
|
||||
|
||||
@@ -203,7 +214,7 @@ impl voprf::Group for Ristretto255 {
|
||||
<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)
|
||||
}
|
||||
|
||||
@@ -215,7 +226,7 @@ impl voprf::Group for Ristretto255 {
|
||||
<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)
|
||||
}
|
||||
|
||||
|
||||
+32
-22
@@ -21,11 +21,12 @@ use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::Output;
|
||||
use digest::core_api::{BlockSizeUser, CoreProxy};
|
||||
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U2, U256};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hybrid_array::Array;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use voprf::{BlindedElement, EvaluationElement};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
@@ -33,7 +34,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use crate::ciphersuite::KeHash;
|
||||
use crate::ciphersuite::{CipherSuite, OprfGroup};
|
||||
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::shared::{NonceLen, STR_CONTEXT};
|
||||
use crate::keypair::{PrivateKey, PublicKey};
|
||||
@@ -44,8 +45,9 @@ use crate::serialization::{SliceExt, i2osp};
|
||||
pub trait KeyExchange
|
||||
where
|
||||
<Self::Hash as CoreProxy>::Core: ProxyHash,
|
||||
<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<<Self::Hash as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<Self::Hash as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<Self::Hash>: ArrayLength,
|
||||
{
|
||||
/// The group used for the key exchange.
|
||||
type Group: Group;
|
||||
@@ -71,12 +73,12 @@ where
|
||||
|
||||
/// Client generates [`KE1Message`](Self::KE1Message) and
|
||||
/// [`KE1State`](Self::KE1State).
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
fn generate_ke1<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<GenerateKe1Result<Self>, ProtocolError>;
|
||||
|
||||
/// 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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -92,7 +94,7 @@ where
|
||||
) -> Self::KE2BuilderData<'a, CS>;
|
||||
|
||||
/// 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>,
|
||||
rng: &mut R,
|
||||
server_s_sk: &PrivateKey<Self::Group>,
|
||||
@@ -107,7 +109,7 @@ where
|
||||
|
||||
/// Client generates [`KE3Message`](Self::KE3Message) and the session key.
|
||||
#[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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -137,7 +139,7 @@ where
|
||||
)]
|
||||
#[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)]
|
||||
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> {
|
||||
@@ -154,17 +156,20 @@ impl<CS: CipherSuite> SerializedCredentialRequest<CS> {
|
||||
/// Returns a [`SerializedCredentialRequest`] deserialized from the given
|
||||
/// `bytes`.
|
||||
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;
|
||||
|
||||
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>;
|
||||
|
||||
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)]
|
||||
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>,
|
||||
masked_response: MaskedResponse<CS>,
|
||||
}
|
||||
@@ -207,7 +212,7 @@ impl<CS: CipherSuite> SerializedCredentialResponse<CS> {
|
||||
/// `bytes`.
|
||||
pub fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
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")?,
|
||||
masked_response: MaskedResponse::deserialize_take(input)?,
|
||||
})
|
||||
@@ -221,16 +226,21 @@ impl<CS: CipherSuite> Serialize for SerializedCredentialResponse<CS>
|
||||
where
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
SerializedCredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
SerializedCredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
type Len = SerializedCredentialResponseLen<CS>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.evaluation_element
|
||||
.clone()
|
||||
.concat(self.masking_nonce)
|
||||
.concat(self.masked_response.serialize())
|
||||
let elem = GenericArray::<u8, <OprfGroup<CS> as voprf::Group>::ElemLen>::from_slice(
|
||||
self.evaluation_element.as_slice(),
|
||||
)
|
||||
.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.
|
||||
pub trait Serialize {
|
||||
/// The length of the serialized types.
|
||||
type Len: ArrayLength<u8>;
|
||||
type Len: ArrayLength;
|
||||
|
||||
/// Serialize [`Self`] to a fixed-length byte array.
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len>;
|
||||
|
||||
+45
-34
@@ -9,14 +9,15 @@
|
||||
use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
|
||||
use digest::{Digest, Mac, Output, OutputSizeUser, Update};
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U1, U2, U32, U256, Unsigned};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hkdf::{Hkdf, HkdfExtract};
|
||||
use hmac::Hmac;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hkdf::SimpleHkdf as Hkdf;
|
||||
use hkdf::SimpleHkdfExtract as HkdfExtract;
|
||||
use hmac::{KeyInit, SimpleHmac};
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
use super::{
|
||||
Deserialize, GenerateKe1Result, KeyExchange, Serialize, SerializedContext,
|
||||
@@ -106,8 +107,9 @@ pub(super) struct DerivedKeys<H: OutputSizeUser> {
|
||||
pub(super) struct Ke2BuilderCommon<G: Group, H: Hash>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
G::Sk: DiffieHellman<G>,
|
||||
{
|
||||
pub(super) server_nonce: GenericArray<u8, NonceLen>,
|
||||
@@ -126,7 +128,7 @@ where
|
||||
// Helper functions
|
||||
|
||||
pub(super) fn generate_ke1<
|
||||
R: RngCore + CryptoRng,
|
||||
R: Rng + CryptoRng,
|
||||
KE: KeyExchange<KE1State = Ke1State<G>, KE1Message = Ke1Message<G>>,
|
||||
G: Group,
|
||||
>(
|
||||
@@ -150,7 +152,7 @@ pub(super) fn generate_ke1<
|
||||
}
|
||||
|
||||
// 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();
|
||||
rng.fill_bytes(&mut nonce_bytes);
|
||||
nonce_bytes
|
||||
@@ -190,11 +192,12 @@ pub(super) fn ke2_builder_common<'a, G, H, CS, R>(
|
||||
where
|
||||
G: Group,
|
||||
H: Hash,
|
||||
R: RngCore + CryptoRng,
|
||||
R: Rng + CryptoRng,
|
||||
CS: CipherSuite,
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
G::Sk: DiffieHellman<G>,
|
||||
CS::KeyExchange: KeyExchange<Group = G, Hash = H>,
|
||||
{
|
||||
@@ -238,8 +241,9 @@ pub(super) fn derive_keys<'a, H: Hash>(
|
||||
) -> Result<DerivedKeys<H>, ProtocolError>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
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>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
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);
|
||||
let mac = mac_hasher.finalize().into_bytes();
|
||||
|
||||
transcript_hasher.update(&mac);
|
||||
Update::update(transcript_hasher, &mac);
|
||||
let finalized_transcript = transcript_hasher.clone().finalize();
|
||||
|
||||
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);
|
||||
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>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
let transcript_digest = transcript_hasher.clone().finalize();
|
||||
let derived_keys = derive_keys::<H>(shared_secrets, &transcript_digest)?;
|
||||
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);
|
||||
server_mac_hasher
|
||||
.verify(server_mac)
|
||||
.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 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);
|
||||
|
||||
let client_mac = client_mac_hasher.finalize().into_bytes();
|
||||
@@ -342,8 +348,9 @@ fn hkdf_expand_label<H: Hash>(
|
||||
) -> Result<Output<H>, ProtocolError>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
let h = Hkdf::<H>::from_prk(secret).map_err(|_| InternalError::HkdfError)?;
|
||||
hkdf_expand_label_extracted(&h, label, context)
|
||||
@@ -356,10 +363,11 @@ fn hkdf_expand_label_extracted<H: Hash>(
|
||||
) -> Result<Output<H>, ProtocolError>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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 label_length = i2osp::<U1>(STR_OPAQUE.len() + label.len())?;
|
||||
@@ -386,8 +394,9 @@ fn derive_secrets<H: Hash>(
|
||||
) -> Result<Output<H>, ProtocolError>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
hkdf_expand_label_extracted::<H>(hkdf, label, hashed_derivation_transcript)
|
||||
}
|
||||
@@ -407,12 +416,14 @@ impl<G: Group> Serialize for Ke1State<G>
|
||||
where
|
||||
// Ke1State: KeSk + Nonce
|
||||
G::SkLen: Add<NonceLen>,
|
||||
Sum<G::SkLen, NonceLen>: ArrayLength<u8>,
|
||||
Sum<G::SkLen, NonceLen>: ArrayLength,
|
||||
{
|
||||
type Len = Sum<G::SkLen, NonceLen>;
|
||||
|
||||
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
|
||||
// Ke1Message: Nonce + KePk
|
||||
NonceLen: Add<G::PkLen>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength<u8>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength,
|
||||
{
|
||||
type Len = Sum<NonceLen, G::PkLen>;
|
||||
|
||||
@@ -476,7 +487,7 @@ impl<G: Group> Ke1MessageIter<G> {
|
||||
impl<G: Group> Ke1MessageIter<G>
|
||||
where
|
||||
NonceLen: Add<G::PkLen>,
|
||||
Ke1MessageIterLen<G>: ArrayLength<u8>,
|
||||
Ke1MessageIterLen<G>: ArrayLength,
|
||||
{
|
||||
pub(crate) fn serialize(&self) -> GenericArray<u8, Ke1MessageIterLen<G>> {
|
||||
self.client_nonce.concat(self.client_e_pk.clone())
|
||||
|
||||
@@ -11,23 +11,19 @@
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::{FixedOutputReset, HashMarker};
|
||||
use ecdsa::{PrimeCurve, SignatureSize, hazmat};
|
||||
use elliptic_curve::{
|
||||
CurveArithmetic, Field, FieldBytes, FieldBytesEncoding, FieldBytesSize, PrimeField, Scalar,
|
||||
SecretKey,
|
||||
};
|
||||
use digest::block_api::{BlockSizeUser, EagerHash};
|
||||
use digest::{Digest, FixedOutputReset, HashMarker};
|
||||
use ecdsa::{EcdsaCurve, SignatureSize};
|
||||
use elliptic_curve::point::NonIdentity;
|
||||
use elliptic_curve::{CurveArithmetic, FieldBytes, ProjectivePoint, SecretKey};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use zeroize::Zeroize;
|
||||
use hybrid_array::ArraySize;
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
use super::{Message, MessageBuilder, SignatureProtocol};
|
||||
use crate::ciphersuite::CipherSuite;
|
||||
use crate::errors::ProtocolError;
|
||||
use crate::key_exchange::group::Group;
|
||||
use crate::key_exchange::group::elliptic_curve::NonIdentity;
|
||||
pub use crate::key_exchange::sigma_i::shared::PreHash;
|
||||
use crate::serialization::SliceExt;
|
||||
|
||||
@@ -39,23 +35,21 @@ pub struct Ecdsa<G, H>(PhantomData<(G, H)>);
|
||||
|
||||
impl<G, H> SignatureProtocol for Ecdsa<G, H>
|
||||
where
|
||||
G: CurveArithmetic + Group<Sk = SecretKey<G>, Pk = NonIdentity<G>> + PrimeCurve,
|
||||
SignatureSize<G>: ArrayLength<u8>,
|
||||
H: Clone
|
||||
+ Default
|
||||
+ BlockSizeUser
|
||||
+ FixedOutputReset<OutputSize = FieldBytesSize<G>>
|
||||
+ HashMarker,
|
||||
G: CurveArithmetic
|
||||
+ Group<Sk = SecretKey<G>, Pk = NonIdentity<ProjectivePoint<G>>>
|
||||
+ EcdsaCurve,
|
||||
SignatureSize<G>: ArrayLength + ArraySize,
|
||||
H: EagerHash + FixedOutputReset + BlockSizeUser + HashMarker + Digest + Clone + Default,
|
||||
{
|
||||
type Group = G;
|
||||
type Signature = Signature<G>;
|
||||
type Signature = ecdsa::Signature<G>;
|
||||
type SignatureLen = SignatureSize<G>;
|
||||
type VerifyState<CS: CipherSuite, KE: Group> = PreHash<H>;
|
||||
|
||||
// We use a manual implementation of `RandomizedPrehashSigner` to use the same
|
||||
// hash for the message as for generating `k`. See
|
||||
// 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,
|
||||
rng: &mut R,
|
||||
message: &Message<CS, KE>,
|
||||
@@ -63,7 +57,7 @@ where
|
||||
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()),
|
||||
)
|
||||
}
|
||||
@@ -74,96 +68,55 @@ where
|
||||
state: Self::VerifyState<CS, KE>,
|
||||
signature: &Self::Signature,
|
||||
) -> Result<(), ProtocolError> {
|
||||
verify(pk, &state.0, &signature.0)
|
||||
verify(pk, &state.0, signature)
|
||||
}
|
||||
|
||||
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> {
|
||||
ecdsa::Signature::from_bytes(&bytes.take_array("signature")?)
|
||||
.map(Signature)
|
||||
ecdsa::Signature::from_bytes(&bytes.take_array("signature")?.into_ha0_4())
|
||||
.map_err(|_| ProtocolError::SerializationError)
|
||||
}
|
||||
}
|
||||
|
||||
fn sign<R, C, H>(sk: &SecretKey<C>, rng: &mut R, pre_hash: &[u8]) -> ecdsa::Signature<C>
|
||||
where
|
||||
R: CryptoRng + RngCore,
|
||||
C: CurveArithmetic + PrimeCurve,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
H: Default + BlockSizeUser + FixedOutputReset<OutputSize = FieldBytesSize<C>> + HashMarker,
|
||||
R: CryptoRng + Rng,
|
||||
C: CurveArithmetic + EcdsaCurve,
|
||||
SignatureSize<C>: ArraySize,
|
||||
H: Digest + BlockSizeUser + FixedOutputReset,
|
||||
{
|
||||
let repr = sk.to_bytes();
|
||||
let order = C::ORDER.encode_field_bytes();
|
||||
let z =
|
||||
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;
|
||||
}
|
||||
}
|
||||
let mut ad = FieldBytes::<C>::default();
|
||||
rng.fill_bytes(&mut ad);
|
||||
ecdsa::hazmat::sign_prehashed_rfc6979::<C, H>(&sk.to_nonzero_scalar(), pre_hash, &ad).0
|
||||
}
|
||||
|
||||
fn verify<C>(
|
||||
pk: &NonIdentity<C>,
|
||||
pk: &NonIdentity<ProjectivePoint<C>>,
|
||||
pre_hash: &[u8],
|
||||
signature: &ecdsa::Signature<C>,
|
||||
) -> Result<(), ProtocolError>
|
||||
where
|
||||
C: CurveArithmetic + PrimeCurve,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
C: CurveArithmetic + EcdsaCurve,
|
||||
SignatureSize<C>: ArraySize,
|
||||
{
|
||||
let z =
|
||||
hazmat::bits2field::<C>(pre_hash).expect("hash output can not be shorter than a scalar");
|
||||
hazmat::verify_prehashed(&pk.0.to_point(), &z, signature)
|
||||
ecdsa::hazmat::verify_prehashed(&pk.to_point(), pre_hash, signature)
|
||||
.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]
|
||||
fn ecdsa() {
|
||||
use std::vec;
|
||||
|
||||
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::{NistP256, PublicKey};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_core::UnwrapErr;
|
||||
use sha2::Sha256;
|
||||
|
||||
use crate::tests::mock_rng::CycleRng;
|
||||
@@ -171,22 +124,24 @@ fn ecdsa() {
|
||||
let mut rng = CycleRng::new(vec![1; 32]);
|
||||
|
||||
let mut message = [0; 1024];
|
||||
OsRng.fill_bytes(&mut message);
|
||||
UnwrapErr(SysRng).fill_bytes(&mut 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 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());
|
||||
|
||||
assert_eq!(signature, custom_signature);
|
||||
|
||||
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
|
||||
.verify_digest(hash.clone(), &signature)
|
||||
.verify_prehash(&hash.clone().finalize(), &signature)
|
||||
.unwrap();
|
||||
verify(&pk, &hash.finalize(), &custom_signature).unwrap();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use self::implementation::HashEddsaImpl;
|
||||
@@ -33,7 +33,7 @@ impl<G: HashEddsaImpl> SignatureProtocol for HashEddsa<G> {
|
||||
type SignatureLen = G::SignatureLen;
|
||||
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,
|
||||
_: &mut R,
|
||||
message: &Message<CS, KE>,
|
||||
@@ -66,7 +66,7 @@ pub(in super::super) mod implementation {
|
||||
|
||||
pub trait HashEddsaImpl: Group {
|
||||
type Signature: Clone + Zeroize;
|
||||
type SignatureLen: ArrayLength<u8>;
|
||||
type SignatureLen: ArrayLength;
|
||||
type VerifyState<CS: CipherSuite, KE: Group>: Clone + Zeroize;
|
||||
|
||||
fn sign<CS: CipherSuite, KE: Group>(
|
||||
|
||||
@@ -10,7 +10,6 @@ use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::{FixedOutput, Output, Update};
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::Sum;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use zeroize::Zeroize;
|
||||
@@ -26,7 +25,7 @@ use crate::key_exchange::{
|
||||
SerializedIdentifier, SerializedIdentifiers,
|
||||
};
|
||||
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.
|
||||
///
|
||||
@@ -242,7 +241,7 @@ impl<CS: CipherSuite, KE: Group> Deserialize for CachedMessage<CS, KE> {
|
||||
credential_response: SerializedCredentialResponse::deserialize_take(input)?,
|
||||
server_nonce: input.take_array("server nonce")?,
|
||||
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>
|
||||
where
|
||||
SerializedCredentialRequestLen<CS>: ArrayLength<u8> + Add<Ke1MessageIterLen<KE>>,
|
||||
SerializedCredentialRequestLen<CS>: ArrayLength + Add<Ke1MessageIterLen<KE>>,
|
||||
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>:
|
||||
ArrayLength<u8> + Add<SerializedCredentialResponseLen<CS>>,
|
||||
ArrayLength + Add<SerializedCredentialResponseLen<CS>>,
|
||||
Sum<
|
||||
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
|
||||
SerializedCredentialResponseLen<CS>,
|
||||
>: ArrayLength<u8> + Add<NonceLen>,
|
||||
>: ArrayLength + Add<NonceLen>,
|
||||
Sum<
|
||||
Sum<
|
||||
Sum<SerializedCredentialRequestLen<CS>, Ke1MessageIterLen<KE>>,
|
||||
SerializedCredentialResponseLen<CS>,
|
||||
>,
|
||||
NonceLen,
|
||||
>: ArrayLength<u8> + Add<KE::PkLen>,
|
||||
>: ArrayLength + Add<KE::PkLen>,
|
||||
Sum<
|
||||
Sum<
|
||||
Sum<
|
||||
@@ -287,26 +286,26 @@ where
|
||||
NonceLen,
|
||||
>,
|
||||
KE::PkLen,
|
||||
>: ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>,
|
||||
CachedMessageLen<CS, KE>: ArrayLength<u8>,
|
||||
>: ArrayLength + Add<OutputSize<KeHash<CS>>>,
|
||||
CachedMessageLen<CS, KE>: ArrayLength,
|
||||
// Ke1MessageIter
|
||||
NonceLen: Add<KE::PkLen>,
|
||||
Ke1MessageIterLen<KE>: ArrayLength<u8>,
|
||||
Ke1MessageIterLen<KE>: ArrayLength,
|
||||
// CredentialResponseParts
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
SerializedCredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
SerializedCredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
type Len = CachedMessageLen<CS, KE>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.credential_request
|
||||
.serialize()
|
||||
.concat(self.ke1_message.serialize())
|
||||
.concat(self.credential_response.serialize())
|
||||
.concat(self.server_nonce)
|
||||
.concat(self.server_e_pk.clone())
|
||||
.concat(self.server_mac.clone())
|
||||
.cat(self.ke1_message.serialize())
|
||||
.cat(self.credential_response.serialize())
|
||||
.cat(self.server_nonce)
|
||||
.cat(self.server_e_pk.clone())
|
||||
.cat(GenericArray::from_slice(self.server_mac.as_slice()).clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ use core::marker::PhantomData;
|
||||
use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::{Digest, Mac, Output, OutputSizeUser};
|
||||
use digest::block_api::{BlockSizeUser, CoreProxy, SmallBlockSizeUser};
|
||||
use digest::{Mac, Output, OutputSizeUser};
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hmac::Hmac;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hmac::{KeyInit, SimpleHmac};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use subtle::{ConstantTimeEq, CtOption};
|
||||
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::keypair::{KeyPair, PrivateKey, PublicKey};
|
||||
use crate::opaque::Identifiers;
|
||||
use crate::serialization::{SliceExt, UpdateExt};
|
||||
use crate::serialization::{ConcatExt, SliceExt, UpdateExt};
|
||||
|
||||
/// The SIGMA-I key exchange implementation
|
||||
///
|
||||
@@ -95,7 +95,7 @@ pub trait SignatureProtocol {
|
||||
/// The signature.
|
||||
type Signature: Clone + Zeroize;
|
||||
/// 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
|
||||
/// pre-hash for curves that support that, otherwise the [`Message`] to
|
||||
/// verify is stored via [`CachedMessage`].
|
||||
@@ -111,7 +111,7 @@ pub trait SignatureProtocol {
|
||||
/// The returned [`VerifyState`](Self::VerifyState) will be passed to
|
||||
/// [`verify()`](Self::verify) and must contain the necessary
|
||||
/// 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,
|
||||
rng: &mut R,
|
||||
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>
|
||||
where
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
{
|
||||
server_nonce: GenericArray<u8, NonceLen>,
|
||||
#[derive_where(skip(Zeroize))]
|
||||
@@ -223,37 +224,42 @@ where
|
||||
)]
|
||||
#[derive_where(Clone, ZeroizeOnDrop)]
|
||||
#[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,
|
||||
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
|
||||
KE::Sk: DiffieHellman<KE>,
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
{
|
||||
type Group = SIG::Group;
|
||||
type Hash = KEH;
|
||||
|
||||
type KE1State = Ke1State<KE>;
|
||||
type KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
|
||||
type KE1Message = Ke1Message<KE>;
|
||||
type KE2Builder<'a, CS: CipherSuite<KeyExchange = Self>> = Ke2Builder<'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 KE2State<CS: CipherSuite> = Ke2State<CS, SIG, KE>;
|
||||
type KE2Message = Ke2Message<SIG, KE, KEH>;
|
||||
type KE3Message = Ke3Message<SIG, KEH>;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
fn generate_ke1<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -287,13 +293,13 @@ where
|
||||
&transcript_hasher.finalize(),
|
||||
)?;
|
||||
|
||||
let mut server_mac =
|
||||
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
|
||||
let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
|
||||
.map_err(|_| InternalError::HmacError)?;
|
||||
server_mac.update_iter(identifiers.server.iter());
|
||||
let server_mac = server_mac.finalize().into_bytes();
|
||||
|
||||
let mut client_mac =
|
||||
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
|
||||
let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
|
||||
.map_err(|_| InternalError::HmacError)?;
|
||||
client_mac.update_iter(identifiers.client.iter());
|
||||
let client_mac = client_mac.finalize().into_bytes();
|
||||
|
||||
@@ -331,7 +337,7 @@ where
|
||||
&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>,
|
||||
rng: &mut R,
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -397,8 +403,8 @@ where
|
||||
&transcript_hasher.finalize(),
|
||||
)?;
|
||||
|
||||
let mut server_mac =
|
||||
Hmac::<KEH>::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?;
|
||||
let mut server_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km2)
|
||||
.map_err(|_| InternalError::HmacError)?;
|
||||
server_mac.update_iter(identifiers.server.iter());
|
||||
let server_mac = server_mac.finalize().into_bytes();
|
||||
|
||||
@@ -406,8 +412,8 @@ where
|
||||
.then_some(())
|
||||
.ok_or(ProtocolError::InvalidLoginError)?;
|
||||
|
||||
let mut client_mac =
|
||||
Hmac::<KEH>::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?;
|
||||
let mut client_mac = SimpleHmac::<KEH>::new_from_slice(&derived_keys.km3)
|
||||
.map_err(|_| InternalError::HmacError)?;
|
||||
client_mac.update_iter(identifiers.client.iter());
|
||||
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>
|
||||
where
|
||||
SIG::VerifyState<CS, KE>: Deserialize,
|
||||
OutputSize<KeHash<CS>>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
client_s_pk: PublicKey::deserialize_take(input)?,
|
||||
session_key: input.take_array("session key")?,
|
||||
verify_state: SIG::VerifyState::deserialize_take(input)?,
|
||||
expected_mac: input.take_array("expected mac")?,
|
||||
session_key: input.take_array("session key")?.into_ha0_4(),
|
||||
verify_state: SIG::VerifyState::<CS, KE>::deserialize_take(input)?,
|
||||
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>
|
||||
where
|
||||
SIG::VerifyState<CS, KE>: Serialize,
|
||||
OutputSize<KeHash<CS>>: ArrayLength,
|
||||
// Ke2State: ((SigPk + Hash) + VerifyState) + Hash
|
||||
<SIG::Group as Group>::PkLen: Add<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>>:
|
||||
ArrayLength<u8> + Add<OutputSize<KeHash<CS>>>,
|
||||
Ke2StateLen<CS, SIG, KE>: ArrayLength<u8>,
|
||||
ArrayLength + Add<OutputSize<KeHash<CS>>>,
|
||||
Ke2StateLen<CS, SIG, KE>: ArrayLength,
|
||||
{
|
||||
type Len = Ke2StateLen<CS, SIG, KE>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.client_s_pk
|
||||
.serialize()
|
||||
.concat(self.session_key.clone())
|
||||
.concat(self.verify_state.serialize())
|
||||
.concat(self.expected_mac.clone())
|
||||
Concat::concat(
|
||||
Concat::concat(
|
||||
Concat::concat(
|
||||
self.client_s_pk.serialize(),
|
||||
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>
|
||||
where
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
server_nonce: input.take_array("server nonce")?,
|
||||
server_e_pk: PublicKey::deserialize_take(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>
|
||||
where
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
// Ke2Message: ((Nonce + KePk) + Signature) + Hash
|
||||
NonceLen: Add<KE::PkLen>,
|
||||
Sum<NonceLen, KE::PkLen>: ArrayLength<u8> + Add<SIG::SignatureLen>,
|
||||
Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength<u8> + Add<OutputSize<KEH>>,
|
||||
Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength<u8>,
|
||||
Sum<NonceLen, KE::PkLen>: ArrayLength + Add<SIG::SignatureLen>,
|
||||
Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>: ArrayLength + Add<OutputSize<KEH>>,
|
||||
Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>: ArrayLength,
|
||||
{
|
||||
type Len = Sum<Sum<Sum<NonceLen, KE::PkLen>, SIG::SignatureLen>, OutputSize<KEH>>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.server_nonce
|
||||
.concat(self.server_e_pk.serialize())
|
||||
.concat(SIG::serialize_signature(&self.signature))
|
||||
.concat(self.mac.clone())
|
||||
.cat(self.server_e_pk.serialize())
|
||||
.cat(SIG::serialize_signature(&self.signature))
|
||||
.cat(GenericArray::from_slice(self.mac.as_slice()).clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<SIG: SignatureProtocol, KEH: Hash> Deserialize for Ke3Message<SIG, KEH>
|
||||
where
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
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>
|
||||
where
|
||||
KEH::Core: ProxyHash,
|
||||
<KEH::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<KEH::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<KEH as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<KEH>: ArrayLength,
|
||||
// Ke2Message: Signature + Hash
|
||||
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>>;
|
||||
|
||||
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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use generic_array::GenericArray;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use self::implementation::PureEddsaImpl;
|
||||
@@ -34,7 +34,7 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
|
||||
type SignatureLen = G::SignatureLen;
|
||||
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,
|
||||
_: &mut R,
|
||||
message: &Message<CS, KE>,
|
||||
@@ -51,13 +51,13 @@ impl<G: PureEddsaImpl> SignatureProtocol for PureEddsa<G> {
|
||||
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> {
|
||||
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 {
|
||||
@@ -67,7 +67,7 @@ pub(in super::super) mod implementation {
|
||||
|
||||
pub trait PureEddsaImpl: Group {
|
||||
type Signature: Clone + Zeroize;
|
||||
type SignatureLen: ArrayLength<u8>;
|
||||
type SignatureLen: ArrayLength;
|
||||
|
||||
fn sign<CS: CipherSuite, KE: Group>(
|
||||
sk: &Self::Sk,
|
||||
|
||||
@@ -16,24 +16,30 @@ use crate::serialization::SliceExt;
|
||||
|
||||
/// Pre-hash of the message to be verified.
|
||||
#[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
|
||||
#[derive_where(Copy; <H::OutputSize as ArrayLength<u8>>::ArrayType)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde::Deserialize, serde::Serialize),
|
||||
serde(bound = "")
|
||||
)]
|
||||
#[allow(dead_code)]
|
||||
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> {
|
||||
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;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.0.clone()
|
||||
GenericArray::from_slice(self.0.as_slice()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,11 @@ use core::marker::PhantomData;
|
||||
use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::{Digest, Output, OutputSizeUser};
|
||||
use generic_array::sequence::Concat;
|
||||
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
|
||||
use digest::{Output, OutputSizeUser};
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use subtle::{ConstantTimeEq, CtOption};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
@@ -34,7 +33,7 @@ use crate::key_exchange::shared::{self, NonceLen};
|
||||
pub use crate::key_exchange::shared::{DiffieHellman, Ke1Message, Ke1State};
|
||||
use crate::keypair::{PrivateKey, PublicKey};
|
||||
use crate::opaque::Identifiers;
|
||||
use crate::serialization::SliceExt;
|
||||
use crate::serialization::{ConcatExt, SliceExt};
|
||||
|
||||
////////////////////////////
|
||||
// High-level API Structs //
|
||||
@@ -79,8 +78,9 @@ pub struct Ke2State<H: OutputSizeUser> {
|
||||
pub struct Ke2Builder<G: Group, H: Hash>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
server_nonce: GenericArray<u8, NonceLen>,
|
||||
transcript_hasher: H,
|
||||
@@ -104,8 +104,9 @@ where
|
||||
pub struct Ke2Message<G: Group, H: Hash>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
pub(super) server_nonce: GenericArray<u8, NonceLen>,
|
||||
#[derive_where(skip(Zeroize))]
|
||||
@@ -123,8 +124,9 @@ where
|
||||
pub struct Ke3Message<H: Hash>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
pub(super) mac: Output<H>,
|
||||
}
|
||||
@@ -138,8 +140,9 @@ impl<G: Group + 'static, H: Hash> KeyExchange for TripleDh<G, H>
|
||||
where
|
||||
G::Sk: DiffieHellman<G>,
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
type Group = G;
|
||||
type Hash = H;
|
||||
@@ -153,13 +156,13 @@ where
|
||||
type KE2Message = Ke2Message<G, H>;
|
||||
type KE3Message = Ke3Message<H>;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
fn generate_ke1<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -201,7 +204,7 @@ where
|
||||
&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>,
|
||||
_: &mut R,
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -319,13 +322,14 @@ where
|
||||
impl<H: Hash> Deserialize for Ke2State<H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
session_key: input.take_array("session key")?,
|
||||
expected_mac: input.take_array("expected mac")?,
|
||||
session_key: input.take_array("session key")?.into_ha0_4(),
|
||||
expected_mac: input.take_array("expected mac")?.into_ha0_4(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -333,26 +337,32 @@ where
|
||||
impl<H: Hash> Serialize for Ke2State<H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
// Ke2State: Hash + Hash
|
||||
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>>;
|
||||
|
||||
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
|
||||
/// `digest` v11.
|
||||
/// TODO: implement via derive after `Hash` gets `Zeroize` support.
|
||||
impl<G: Group, H: Hash> Drop for Ke2Builder<G, H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let Self {
|
||||
@@ -365,7 +375,7 @@ where
|
||||
} = self;
|
||||
|
||||
server_nonce.zeroize();
|
||||
transcript_hasher.reset();
|
||||
digest::Reset::reset(transcript_hasher);
|
||||
shared_secret_1.zeroize();
|
||||
shared_secret_3.zeroize();
|
||||
}
|
||||
@@ -374,22 +384,24 @@ where
|
||||
impl<G: Group, H: Hash> ZeroizeOnDrop for Ke2Builder<G, H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
}
|
||||
|
||||
impl<G: Group, H: Hash> Deserialize for Ke2Message<G, H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(input: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
server_nonce: input.take_array("server nonce")?,
|
||||
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>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
// Ke2Message: (Nonce + KePk) + Hash
|
||||
NonceLen: Add<G::PkLen>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>,
|
||||
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
|
||||
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
|
||||
{
|
||||
type Len = Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.server_nonce
|
||||
.concat(self.server_e_pk.serialize())
|
||||
.concat(self.mac.clone())
|
||||
.cat(self.server_e_pk.serialize())
|
||||
.cat(GenericArray::from_slice(self.mac.as_slice()).clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hash> Deserialize for Ke3Message<H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
fn deserialize_take(bytes: &mut &[u8]) -> Result<Self, ProtocolError> {
|
||||
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>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
OutputSize<H>: ArrayLength,
|
||||
{
|
||||
type Len = OutputSize<H>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.mac.clone()
|
||||
GenericArray::from_slice(self.mac.as_slice()).clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,18 +23,18 @@ use core::marker::PhantomData;
|
||||
use core::ops::Add;
|
||||
|
||||
use derive_where::derive_where;
|
||||
use digest::core_api::BlockSizeUser;
|
||||
use digest::{Digest, Output};
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
||||
use digest::Output;
|
||||
use digest::block_api::{CoreProxy, SmallBlockSizeUser};
|
||||
use generic_array::typenum::{Cmp, IsLess, Le, NonZero, Sum, U256};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::ArraySize;
|
||||
#[allow(deprecated)]
|
||||
use ml_kem::ExpandedKeyEncoding;
|
||||
use ml_kem::kem::{
|
||||
Ciphertext as MlKemCiphertext, Decapsulate, Encapsulate, Kem as MlKemTrait, KeyExport,
|
||||
KeySizeUser, TryKeyInit,
|
||||
};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use subtle::{ConstantTimeEq, CtOption};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
@@ -50,7 +50,7 @@ use crate::hash::{Hash, OutputSize, ProxyHash};
|
||||
use crate::key_exchange::group::Group;
|
||||
use crate::keypair::{PrivateKey, PublicKey};
|
||||
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
|
||||
/// required by OPAQUE (e.g. fixed lengths and serialization hooks).
|
||||
@@ -62,16 +62,16 @@ pub trait KemCoreWrapper {
|
||||
type DecapsulationKey: Clone + ZeroizeOnDrop;
|
||||
|
||||
/// Length (in bytes) of the serialized public key.
|
||||
type EncapsulationKeyLen: ArrayLength<u8>;
|
||||
type EncapsulationKeyLen: ArrayLength + ArraySize;
|
||||
/// Length (in bytes) of the serialized secret key.
|
||||
type DecapsulationKeyLen: ArrayLength<u8>;
|
||||
type DecapsulationKeyLen: ArrayLength + ArraySize;
|
||||
/// 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.
|
||||
type SharedSecretLen: ArrayLength<u8>;
|
||||
type SharedSecretLen: ArrayLength + ArraySize;
|
||||
|
||||
/// Generates a fresh KEM key pair.
|
||||
fn generate<R: RngCore + CryptoRng>(
|
||||
fn generate<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError>;
|
||||
|
||||
@@ -98,7 +98,7 @@ pub trait KemCoreWrapper {
|
||||
/// Encapsulates to the given public key, returning the ciphertext and
|
||||
/// shared secret.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn encapsulate<R: RngCore + CryptoRng>(
|
||||
fn encapsulate<R: Rng + CryptoRng>(
|
||||
key: &Self::EncapsulationKey,
|
||||
rng: &mut R,
|
||||
) -> Result<
|
||||
@@ -120,7 +120,7 @@ pub trait KemCoreWrapper {
|
||||
/// which is required by `ml-kem 0.3.x`.
|
||||
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;
|
||||
|
||||
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;
|
||||
#[allow(deprecated)]
|
||||
@@ -152,10 +152,10 @@ where
|
||||
K: MlKemTrait,
|
||||
K::EncapsulationKey: Encapsulate<Kem = K> + KeyExport + TryKeyInit + Clone,
|
||||
K::DecapsulationKey: Decapsulate<Kem = K> + ExpandedKeyEncoding + Clone + ZeroizeOnDrop,
|
||||
RcEncapsulationKeyLen<K>: ArrayLength<u8>,
|
||||
RcDecapsulationKeyLen<K>: ArrayLength<u8>,
|
||||
RcCiphertextLen<K>: ArrayLength<u8>,
|
||||
RcSharedSecretLen<K>: ArrayLength<u8>,
|
||||
RcEncapsulationKeyLen<K>: ArrayLength + ArraySize,
|
||||
RcDecapsulationKeyLen<K>: ArrayLength + ArraySize,
|
||||
RcCiphertextLen<K>: ArrayLength + ArraySize,
|
||||
RcSharedSecretLen<K>: ArrayLength + ArraySize,
|
||||
{
|
||||
type EncapsulationKey = K::EncapsulationKey;
|
||||
type DecapsulationKey = K::DecapsulationKey;
|
||||
@@ -164,7 +164,7 @@ where
|
||||
type CiphertextLen = RcCiphertextLen<K>;
|
||||
type SharedSecretLen = RcSharedSecretLen<K>;
|
||||
|
||||
fn generate<R: RngCore + CryptoRng>(
|
||||
fn generate<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> {
|
||||
Ok(K::generate_keypair_from_rng(&mut RngCompat(rng)))
|
||||
@@ -173,7 +173,7 @@ where
|
||||
fn serialize_encapsulation_key(
|
||||
key: &Self::EncapsulationKey,
|
||||
) -> 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(
|
||||
@@ -189,7 +189,7 @@ where
|
||||
fn serialize_decapsulation_key(
|
||||
key: &Self::DecapsulationKey,
|
||||
) -> 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(
|
||||
@@ -203,7 +203,7 @@ where
|
||||
.map_err(|_| ProtocolError::SerializationError)
|
||||
}
|
||||
|
||||
fn encapsulate<R: RngCore + CryptoRng>(
|
||||
fn encapsulate<R: Rng + CryptoRng>(
|
||||
key: &Self::EncapsulationKey,
|
||||
rng: &mut R,
|
||||
) -> Result<
|
||||
@@ -215,8 +215,8 @@ where
|
||||
> {
|
||||
let (ciphertext, shared) = key.encapsulate_with_rng(&mut RngCompat(rng));
|
||||
Ok((
|
||||
GenericArray::clone_from_slice(ciphertext.as_slice()),
|
||||
GenericArray::clone_from_slice(shared.as_slice()),
|
||||
GenericArray::from_slice(ciphertext.as_slice()).clone(),
|
||||
GenericArray::from_slice(shared.as_slice()).clone(),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ where
|
||||
let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice())
|
||||
.map_err(|_| ProtocolError::SerializationError)?;
|
||||
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
|
||||
@@ -281,8 +281,10 @@ pub struct KemKe1Message<G: Group, K: KemCoreWrapper> {
|
||||
pub struct KemKe2State<K: KemCoreWrapper, H: Hash>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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>,
|
||||
kem_encapsulation_key: GenericArray<u8, K::EncapsulationKeyLen>,
|
||||
@@ -295,8 +297,10 @@ where
|
||||
pub struct KemKe2Builder<G: Group, H: Hash, K: KemCoreWrapper>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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>,
|
||||
transcript_hasher: H,
|
||||
@@ -323,8 +327,10 @@ where
|
||||
pub struct KemKe2Message<G: Group, H: Hash, K: KemCoreWrapper>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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>,
|
||||
kem_ciphertext: GenericArray<u8, K::CiphertextLen>,
|
||||
@@ -338,13 +344,15 @@ where
|
||||
G: Group,
|
||||
H: Hash,
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
|
||||
OutputSize<H>: ArrayLength,
|
||||
K: KemCoreWrapper,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.server_nonce.zeroize();
|
||||
self.transcript_hasher.reset();
|
||||
digest::Digest::reset(&mut self.transcript_hasher);
|
||||
self.shared_secret_1.zeroize();
|
||||
self.shared_secret_3.zeroize();
|
||||
self.kem_shared_secret.zeroize();
|
||||
@@ -357,8 +365,10 @@ where
|
||||
G: Group,
|
||||
H: Hash,
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
|
||||
OutputSize<H>: ArrayLength,
|
||||
K: KemCoreWrapper,
|
||||
{
|
||||
}
|
||||
@@ -369,11 +379,13 @@ where
|
||||
G::Sk: shared::DiffieHellman<G>,
|
||||
H: Hash,
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
Le<<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: Cmp<U256>,
|
||||
OutputSize<H>: ArrayLength,
|
||||
K: KemCoreWrapper,
|
||||
NonceLen: Add<K::EncapsulationKeyLen>,
|
||||
Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength<u8>,
|
||||
Sum<NonceLen, K::EncapsulationKeyLen>: ArrayLength,
|
||||
{
|
||||
type Group = G;
|
||||
type Hash = H;
|
||||
@@ -390,7 +402,7 @@ where
|
||||
type KE2Message = KemKe2Message<G, H, K>;
|
||||
type KE3Message = KemKe3Message<H>;
|
||||
|
||||
fn generate_ke1<R: RngCore + CryptoRng>(
|
||||
fn generate_ke1<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
) -> Result<GenerateKe1Result<Self>, ProtocolError> {
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -440,8 +452,11 @@ where
|
||||
let (kem_ciphertext, kem_shared_secret) = K::encapsulate(&encapsulation_key, rng)?;
|
||||
|
||||
let mut transcript_hasher = transcript_hasher;
|
||||
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice());
|
||||
transcript_hasher.update(kem_ciphertext.as_slice());
|
||||
digest::Digest::update(
|
||||
&mut transcript_hasher,
|
||||
ke1_message.kem_encapsulation_key.as_slice(),
|
||||
);
|
||||
digest::Digest::update(&mut transcript_hasher, kem_ciphertext.as_slice());
|
||||
|
||||
Ok(KemKe2Builder {
|
||||
server_nonce,
|
||||
@@ -462,7 +477,7 @@ where
|
||||
(&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>,
|
||||
_: &mut R,
|
||||
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,
|
||||
credential_request: SerializedCredentialRequest<CS>,
|
||||
ke1_message: Self::KE1Message,
|
||||
@@ -537,8 +552,14 @@ where
|
||||
ke2_message.dh_message.server_nonce,
|
||||
&ke2_message.dh_message.server_e_pk.serialize(),
|
||||
);
|
||||
transcript_hasher.update(ke1_message.kem_encapsulation_key.as_slice());
|
||||
transcript_hasher.update(ke2_message.kem_ciphertext.as_slice());
|
||||
digest::Digest::update(
|
||||
&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
|
||||
.dh_state
|
||||
@@ -606,14 +627,14 @@ impl<G: Group, K: KemCoreWrapper> Serialize for KemKe1State<G, K>
|
||||
where
|
||||
Ke1State<G>: Serialize,
|
||||
<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>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.dh_state
|
||||
.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
|
||||
Ke1Message<G>: Serialize,
|
||||
<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>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.dh_message
|
||||
.serialize()
|
||||
.concat(self.kem_encapsulation_key.clone())
|
||||
.cat(self.kem_encapsulation_key.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: KemCoreWrapper, H: Hash> Deserialize for KemKe2State<K, H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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> {
|
||||
Ok(Self {
|
||||
@@ -659,16 +682,18 @@ where
|
||||
impl<K: KemCoreWrapper, H: Hash> Serialize for KemKe2State<K, H>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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> as Serialize>::Len: Add<K::EncapsulationKeyLen>,
|
||||
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>:
|
||||
ArrayLength<u8> + Add<K::CiphertextLen>,
|
||||
ArrayLength + Add<K::CiphertextLen>,
|
||||
Sum<
|
||||
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
|
||||
K::CiphertextLen,
|
||||
>: ArrayLength<u8>,
|
||||
>: ArrayLength,
|
||||
{
|
||||
type Len = Sum<
|
||||
Sum<<super::tripledh::Ke2State<H> as Serialize>::Len, K::EncapsulationKeyLen>,
|
||||
@@ -678,16 +703,18 @@ where
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.base_state
|
||||
.serialize()
|
||||
.concat(self.kem_encapsulation_key.clone())
|
||||
.concat(self.server_kem_ciphertext.clone())
|
||||
.cat(self.kem_encapsulation_key.clone())
|
||||
.cat(self.server_kem_ciphertext.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group, H: Hash, K: KemCoreWrapper> Deserialize for KemKe2Message<G, H, K>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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> {
|
||||
Ok(Self {
|
||||
@@ -700,21 +727,21 @@ where
|
||||
impl<G: Group, H: Hash, K: KemCoreWrapper> Serialize for KemKe2Message<G, H, K>
|
||||
where
|
||||
H::Core: ProxyHash,
|
||||
<H::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
|
||||
Le<<H::Core as BlockSizeUser>::BlockSize, U256>: NonZero,
|
||||
<<H as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess<U256>,
|
||||
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>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength<u8> + Add<OutputSize<H>>,
|
||||
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength<u8>,
|
||||
Sum<NonceLen, G::PkLen>: ArrayLength + Add<OutputSize<H>>,
|
||||
Sum<Sum<NonceLen, G::PkLen>, OutputSize<H>>: ArrayLength,
|
||||
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 as Add<K::CiphertextLen>>::Output:
|
||||
ArrayLength<u8>,
|
||||
ArrayLength,
|
||||
{
|
||||
type Len = Sum<<super::tripledh::Ke2Message<G, H> as Serialize>::Len, K::CiphertextLen>;
|
||||
|
||||
fn serialize(&self) -> GenericArray<u8, Self::Len> {
|
||||
self.dh_message
|
||||
.serialize()
|
||||
.concat(self.kem_ciphertext.clone())
|
||||
self.dh_message.serialize().cat(self.kem_ciphertext.clone())
|
||||
}
|
||||
}
|
||||
|
||||
+43
-35
@@ -13,7 +13,7 @@
|
||||
use derive_where::derive_where;
|
||||
use digest::{Output, OutputSizeUser};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
use crate::ciphersuite::CipherSuite;
|
||||
use crate::errors::ProtocolError;
|
||||
@@ -32,11 +32,7 @@ use crate::serialization::SliceExt;
|
||||
))
|
||||
)]
|
||||
#[derive_where(Clone)]
|
||||
#[derive_where(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)))]
|
||||
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk, SK)]
|
||||
pub struct KeyPair<G: Group, SK: Clone = PrivateKey<G>> {
|
||||
pk: PublicKey<G>,
|
||||
sk: SK,
|
||||
@@ -60,7 +56,7 @@ impl<G: Group, SK: Clone> KeyPair<G, SK> {
|
||||
}
|
||||
|
||||
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 pk = G::public_key(&sk);
|
||||
Self {
|
||||
@@ -70,7 +66,7 @@ impl<G: Group> KeyPair<G> {
|
||||
}
|
||||
|
||||
/// 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();
|
||||
rng.fill_bytes(&mut scalar_bytes);
|
||||
let sk = G::derive_scalar(scalar_bytes).unwrap();
|
||||
@@ -133,7 +129,7 @@ where
|
||||
impl<G: Group> PrivateKey<G> {
|
||||
/// Private-key signing implementation
|
||||
pub(crate) fn sign<
|
||||
R: CryptoRng + RngCore,
|
||||
R: CryptoRng + Rng,
|
||||
CS: CipherSuite,
|
||||
SIG: SignatureProtocol<Group = G>,
|
||||
KE: Group,
|
||||
@@ -152,7 +148,7 @@ pub trait PrivateKeySerialization<G: Group>: Clone {
|
||||
/// Custom error type that can be passed down to `ProtocolError::Custom`
|
||||
type Error;
|
||||
/// Serialization size in bytes.
|
||||
type Len: ArrayLength<u8>;
|
||||
type Len: ArrayLength;
|
||||
|
||||
/// Serialization into bytes
|
||||
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`].
|
||||
pub trait OprfSeedSerialization<H, E>: Sized {
|
||||
/// Serialization size in bytes.
|
||||
type Len: ArrayLength<u8>;
|
||||
type Len: ArrayLength;
|
||||
|
||||
/// Serialization into bytes
|
||||
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>>;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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>> {
|
||||
Ok(Self(
|
||||
input
|
||||
.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)]
|
||||
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
|
||||
/// [`Self::derive_random`]
|
||||
fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
|
||||
@@ -297,9 +301,6 @@ impl<G: Group> KeyPair<G> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hkdf::Hkdf;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use super::*;
|
||||
use crate::ciphersuite::{KeGroup, OprfHash};
|
||||
use crate::{
|
||||
@@ -309,6 +310,9 @@ mod tests {
|
||||
ServerLoginParameters, ServerLoginStartResult, ServerRegistration,
|
||||
ServerRegistrationStartResult, ServerSetup,
|
||||
};
|
||||
use hkdf::Hkdf;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_core::UnwrapErr;
|
||||
|
||||
macro_rules! test {
|
||||
($mod:ident, $point:ty) => {
|
||||
@@ -323,7 +327,7 @@ mod tests {
|
||||
fn pub_from_priv(kp in KeyPair::<$point>::uniform_keypair_strategy()) {
|
||||
let pk = kp.public();
|
||||
let sk = kp.private();
|
||||
prop_assert_eq!(&sk.public_key(), pk);
|
||||
prop_assert_eq!(sk.public_key().serialize(), pk.serialize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -380,23 +384,24 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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 sk = RemoteKey(sk);
|
||||
let keypair = KeyPair::new(sk, pk);
|
||||
|
||||
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 {
|
||||
message,
|
||||
state: client,
|
||||
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||
} = ClientRegistration::<Default>::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes())
|
||||
.unwrap();
|
||||
let ServerRegistrationStartResult { message, .. } =
|
||||
ServerRegistration::start(&server_setup, message, &[]).unwrap();
|
||||
let ClientRegistrationFinishResult { message, .. } = client
|
||||
.finish(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
PASSWORD.as_bytes(),
|
||||
message,
|
||||
ClientRegistrationFinishParameters::default(),
|
||||
@@ -407,9 +412,9 @@ mod tests {
|
||||
let ClientLoginStartResult {
|
||||
message,
|
||||
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(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
&server_setup,
|
||||
Some(file),
|
||||
message,
|
||||
@@ -425,7 +430,7 @@ mod tests {
|
||||
} = builder.build(shared_secret).unwrap();
|
||||
let ClientLoginFinishResult { message, .. } = client
|
||||
.finish(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
PASSWORD.as_bytes(),
|
||||
message,
|
||||
ClientLoginFinishParameters::default(),
|
||||
@@ -438,22 +443,25 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn remote_seed() {
|
||||
let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default());
|
||||
OsRng.fill_bytes(&mut oprf_seed.0);
|
||||
let mut oprf_seed = RemoteSeed::<OprfHash<Default>>(GenericArray::default().into_ha0_4());
|
||||
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 sk = RemoteKey(sk);
|
||||
let keypair = KeyPair::new(sk, pk);
|
||||
|
||||
let server_setup = ServerSetup::<Default, _, _>::new_with_key_pair_and_seed(
|
||||
&mut OsRng, keypair, oprf_seed,
|
||||
&mut UnwrapErr(SysRng),
|
||||
keypair,
|
||||
oprf_seed,
|
||||
);
|
||||
|
||||
let ClientRegistrationStartResult {
|
||||
message,
|
||||
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 mut ikm = GenericArray::default();
|
||||
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
|
||||
@@ -464,7 +472,7 @@ mod tests {
|
||||
ServerRegistration::start_with_key_material(&server_setup, ikm, message).unwrap();
|
||||
let ClientRegistrationFinishResult { message, .. } = client
|
||||
.finish(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
PASSWORD.as_bytes(),
|
||||
message,
|
||||
ClientRegistrationFinishParameters::default(),
|
||||
@@ -475,7 +483,7 @@ mod tests {
|
||||
let ClientLoginStartResult {
|
||||
message,
|
||||
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 mut ikm = GenericArray::default();
|
||||
Hkdf::<OprfHash<Default>>::from_prk(&km.ikm.0)
|
||||
@@ -483,7 +491,7 @@ mod tests {
|
||||
.expand_multi_info(&km.info, &mut ikm)
|
||||
.unwrap();
|
||||
let builder = ServerLogin::builder_with_key_material(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
&server_setup,
|
||||
ikm,
|
||||
Some(file),
|
||||
@@ -499,7 +507,7 @@ mod tests {
|
||||
} = builder.build(shared_secret).unwrap();
|
||||
let ClientLoginFinishResult { message, .. } = client
|
||||
.finish(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
PASSWORD.as_bytes(),
|
||||
message,
|
||||
ClientLoginFinishParameters::default(),
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ use crate::errors::InternalError;
|
||||
/// Used for the key stretching function in OPAQUE
|
||||
pub trait Ksf: Default {
|
||||
/// Computes the key stretching function
|
||||
fn hash<L: ArrayLength<u8>>(
|
||||
fn hash<L: ArrayLength>(
|
||||
&self,
|
||||
input: GenericArray<u8, L>,
|
||||
) -> Result<GenericArray<u8, L>, InternalError>;
|
||||
@@ -26,7 +26,7 @@ pub trait Ksf: Default {
|
||||
pub struct Identity;
|
||||
|
||||
impl Ksf for Identity {
|
||||
fn hash<L: ArrayLength<u8>>(
|
||||
fn hash<L: ArrayLength>(
|
||||
&self,
|
||||
input: GenericArray<u8, L>,
|
||||
) -> Result<GenericArray<u8, L>, InternalError> {
|
||||
@@ -36,7 +36,7 @@ impl Ksf for Identity {
|
||||
|
||||
#[cfg(feature = "argon2")]
|
||||
impl Ksf for argon2::Argon2<'_> {
|
||||
fn hash<L: ArrayLength<u8>>(
|
||||
fn hash<L: ArrayLength>(
|
||||
&self,
|
||||
input: GenericArray<u8, L>,
|
||||
) -> Result<GenericArray<u8, L>, InternalError> {
|
||||
|
||||
+242
-221
@@ -27,14 +27,14 @@
|
||||
//!
|
||||
//! We will use the following choices in this example:
|
||||
//! ```ignore
|
||||
//! use opaque_ke::CipherSuite;
|
||||
//! use opaque_vx::CipherSuite;
|
||||
//!
|
||||
//! struct Default;
|
||||
//!
|
||||
//! impl CipherSuite for Default {
|
||||
//! type OprfCs = opaque_ke::Ristretto255;
|
||||
//! type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! type Ksf = opaque_ke::ksf::Identity;
|
||||
//! type OprfCs = opaque_vx::Ristretto255;
|
||||
//! type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! type Ksf = opaque_vx::ksf::Identity;
|
||||
//! }
|
||||
//! ```
|
||||
//! 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`
|
||||
//! object:
|
||||
//! ```
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_ke::ServerSetup;
|
||||
//! # use opaque_vx::errors::ProtocolError;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # use opaque_vx::ServerSetup;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! use rand::RngCore;
|
||||
//! use rand::rngs::OsRng;
|
||||
//! use rand::Rng;
|
||||
//! 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);
|
||||
//! # Ok::<(), ProtocolError>(())
|
||||
//! ```
|
||||
@@ -103,30 +104,31 @@
|
||||
//! [`ClientRegistration`] which must be persisted on the client for the final
|
||||
//! step of client registration.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ServerRegistration,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! use opaque_ke::ClientRegistration;
|
||||
//! use rand::RngCore;
|
||||
//! use rand::rngs::OsRng;
|
||||
//! use opaque_vx::ClientRegistration;
|
||||
//! use rand::Rng;
|
||||
//! use rand::rngs::SysRng;
|
||||
//! use rand_core::UnwrapErr;
|
||||
//!
|
||||
//! let mut client_rng = OsRng;
|
||||
//! let mut client_rng = UnwrapErr(SysRng);
|
||||
//! let client_registration_start_result =
|
||||
//! ClientRegistration::<Default>::start(&mut client_rng, b"password")?;
|
||||
//! # Ok::<(), ProtocolError>(())
|
||||
@@ -140,35 +142,36 @@
|
||||
//! [`ServerRegistrationStartResult`], which consists of a
|
||||
//! [`RegistrationResponse`] to be returned to the client.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration,
|
||||
//! # ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # 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_registration_start_result = ServerRegistration::<Default>::start(
|
||||
//! &server_setup,
|
||||
@@ -188,35 +191,36 @@
|
||||
//! which can be used optionally as described in the [Export Key](#export-key)
|
||||
//! section.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ServerRegistration, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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]")?;
|
||||
//! use opaque_ke::ClientRegistrationFinishParameters;
|
||||
//! use opaque_vx::ClientRegistrationFinishParameters;
|
||||
//!
|
||||
//! let client_registration_finish_result = client_registration_start_result.state.finish(
|
||||
//! &mut client_rng,
|
||||
@@ -236,32 +240,33 @@
|
||||
//! [`ServerRegistration::serialize`] to store the password file for use during
|
||||
//! the login protocol.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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
|
||||
//! must be persisted on the client for the final step of client login.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ServerRegistration, ServerLogin, CredentialFinalization,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! use opaque_ke::ClientLogin;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # 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")?;
|
||||
//! # Ok::<(), ProtocolError>(())
|
||||
//! ```
|
||||
@@ -323,32 +329,33 @@
|
||||
//! a [`ServerLogin`] which must be persisted on the server for the final step
|
||||
//! of login.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! use opaque_ke::{ServerLogin, ServerLoginParameters};
|
||||
//! use opaque_vx::{ServerLogin, ServerLoginParameters};
|
||||
//!
|
||||
//! 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(
|
||||
//! &mut server_rng,
|
||||
//! &server_setup,
|
||||
@@ -393,32 +400,33 @@
|
||||
//! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key)
|
||||
//! which will match the server's session key upon a successful login.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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 =
|
||||
//! # 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(
|
||||
//! &mut client_rng,
|
||||
@@ -450,32 +458,33 @@
|
||||
//! to produce an output consisting of the `session_key` sequence of bytes which
|
||||
//! will match the client's session key upon a successful login.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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
|
||||
//! [`ClientRegistrationFinishResult`]) matches this field during login.
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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]")?;
|
||||
//! // During registration, the client obtains a ClientRegistrationFinishResult with
|
||||
@@ -644,32 +654,33 @@
|
||||
//! You can access the export key from the `export_key` field of
|
||||
//! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`].
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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]")?;
|
||||
//! // During registration...
|
||||
@@ -727,20 +738,20 @@
|
||||
//! the ciphersuite as follows:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use opaque_ke::CipherSuite;
|
||||
//! use opaque_vx::CipherSuite;
|
||||
//!
|
||||
//! struct KemSuite;
|
||||
//!
|
||||
//! impl CipherSuite for KemSuite {
|
||||
//! type OprfCs = opaque_ke::Ristretto255;
|
||||
//! type KeyExchange = opaque_ke::TripleDhKem<opaque_ke::Ristretto255, sha2::Sha512, opaque_ke::ml_kem::MlKem768>;
|
||||
//! type Ksf = opaque_ke::ksf::Identity;
|
||||
//! type OprfCs = opaque_vx::Ristretto255;
|
||||
//! type KeyExchange = opaque_vx::TripleDhKem<opaque_vx::Ristretto255, sha2::Sha512, opaque_vx::ml_kem::MlKem768>;
|
||||
//! type Ksf = opaque_vx::ksf::Identity;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## 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 corresponding password file established during registration. This
|
||||
//! username may or may not coincide with the server-side identifier; however,
|
||||
@@ -756,32 +767,33 @@
|
||||
//! [`ClientRegistrationFinishParameters`] in [Client Registration
|
||||
//! Finish](#client-registration-finish):
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, Identifiers, ServerRegistration, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 client_registration_finish_result = client_registration_start_result.state.finish(
|
||||
@@ -802,32 +814,33 @@
|
||||
//! The same identifiers must also be supplied using [`ServerLoginParameters`]
|
||||
//! in [Server Login Start](#server-login-start):
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, CredentialFinalization, Identifiers, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # use opaque_ke::{ServerLogin, ServerLoginParameters};
|
||||
//! # use opaque_vx::{ServerLogin, ServerLoginParameters};
|
||||
//! # 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(
|
||||
//! &mut server_rng,
|
||||
//! &server_setup,
|
||||
@@ -859,32 +872,33 @@
|
||||
//! as well as [`ClientLoginFinishParameters`] in [Client Login
|
||||
//! Finish](#client-login-finish):
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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
|
||||
//! Finish](#server-login-finish):
|
||||
//! ```
|
||||
//! # use opaque_ke::{
|
||||
//! # use opaque_vx::{
|
||||
//! # errors::ProtocolError,
|
||||
//! # ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, ClientLogin, ClientLoginFinishParameters, Identifiers, ServerLogin, ServerLoginParameters, CredentialFinalization, ServerSetup,
|
||||
//! # ksf::Identity,
|
||||
//! # };
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # use rand::{rngs::OsRng, RngCore};
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # use rand::{rngs::SysRng, Rng};
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut client_rng,
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let mut server_rng = OsRng;
|
||||
//! # let mut server_rng = UnwrapErr(SysRng);
|
||||
//! # 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 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
|
||||
//! "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
|
||||
//! login phase, the client and server can specify this context using:
|
||||
//! - 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.
|
||||
//! ```
|
||||
//! # 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 rand::rngs::OsRng;
|
||||
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
|
||||
//! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, ServerRegistration, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
|
||||
//! # use rand::rngs::SysRng;
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//!
|
||||
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[derive(Debug, thiserror::Error)]
|
||||
//! # #[error("test error")]
|
||||
@@ -1034,9 +1051,9 @@
|
||||
//! # Ok(<<Ristretto255 as Group>::Sk as DiffieHellman<Ristretto255>>::diffie_hellman(&self.0, pk.to_group_type()))
|
||||
//! # }
|
||||
//! # }
|
||||
//! use opaque_ke::{ServerLogin, ServerLoginParameters, ServerSetup};
|
||||
//! use opaque_ke::keypair::{KeyPair, PrivateKeySerialization};
|
||||
//! use opaque_ke::errors::ProtocolError;
|
||||
//! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerSetup};
|
||||
//! use opaque_vx::keypair::{KeyPair, PrivateKeySerialization};
|
||||
//! use opaque_vx::errors::ProtocolError;
|
||||
//!
|
||||
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
|
||||
//! 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::serialize_pk(&pk);
|
||||
//! # let public_key = PublicKey::deserialize(&pk).unwrap();
|
||||
//! # 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 server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key_pair(&mut server_rng, keypair);
|
||||
//!
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut OsRng,
|
||||
//! # &mut UnwrapErr(SysRng),
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # 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 client_login_start_result = ClientLogin::<Default>::start(
|
||||
//! # &mut OsRng,
|
||||
//! # &mut UnwrapErr(SysRng),
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
|
||||
@@ -1102,24 +1119,26 @@
|
||||
//! # use digest::Output;
|
||||
//! # use generic_array::{GenericArray, typenum::U0};
|
||||
//! # use hkdf::Hkdf;
|
||||
//! # use opaque_ke::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
|
||||
//! # use rand::rngs::OsRng;
|
||||
//! # use rand::RngCore;
|
||||
//! # type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
|
||||
//! # use opaque_vx::{CipherSuite, ClientLogin, ClientRegistration, ClientRegistrationFinishParameters, keypair::{PrivateKey, PublicKey}, key_exchange::{KeyExchange, group::Group, tripledh::DiffieHellman}};
|
||||
//! # use rand::rngs::SysRng;
|
||||
//! # use rand::Rng;
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//!
|
||||
//! type Ristretto255 = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Group;
|
||||
//! # type Hash = <<Default as CipherSuite>::KeyExchange as KeyExchange>::Hash;
|
||||
//! # type OprfGroup = <<Default as CipherSuite>::OprfCs as voprf::CipherSuite>::Group;
|
||||
//! # struct Default;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for Default {
|
||||
//! # type OprfCs = p256::NistP256;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_ke::ksf::Identity;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
//! # type Ksf = opaque_vx::ksf::Identity;
|
||||
//! # }
|
||||
//! # #[derive(Debug, thiserror::Error)]
|
||||
//! # #[error("test error")]
|
||||
@@ -1143,9 +1162,9 @@
|
||||
//! # 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_ke::keypair::{KeyPair, OprfSeedSerialization};
|
||||
//! use opaque_ke::errors::ProtocolError;
|
||||
//! use opaque_vx::{ServerLogin, ServerLoginParameters, ServerRegistration, ServerSetup};
|
||||
//! use opaque_vx::keypair::{KeyPair, OprfSeedSerialization};
|
||||
//! use opaque_vx::errors::ProtocolError;
|
||||
//!
|
||||
//! // Implement if you intend to use `ServerSetup::de/serialize` instead of `serde`.
|
||||
//! impl OprfSeedSerialization<sha2::Sha512, YourRemoteSecretsError> for YourRemoteSeed {
|
||||
@@ -1160,20 +1179,20 @@
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default());
|
||||
//! # OsRng.fill_bytes(&mut oprf_seed.0);
|
||||
//! # let sk = Ristretto255::random_sk(&mut OsRng);
|
||||
//! # let mut oprf_seed = YourRemoteSeed(GenericArray::default().into_ha0_4());
|
||||
//! # UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0);
|
||||
//! # let sk = Ristretto255::random_sk(&mut UnwrapErr(SysRng));
|
||||
//! # let pk = Ristretto255::public_key(&sk);
|
||||
//! # let pk = Ristretto255::serialize_pk(&pk);
|
||||
//! # let public_key = PublicKey::deserialize(&pk).unwrap();
|
||||
//! # 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 server_setup = ServerSetup::<Default, YourRemoteKey, YourRemoteSeed>::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed);
|
||||
//!
|
||||
//! // Incoming registration ...
|
||||
//! # let client_registration_start_result = ClientRegistration::<Default>::start(
|
||||
//! # &mut OsRng,
|
||||
//! # &mut UnwrapErr(SysRng),
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//!
|
||||
@@ -1189,12 +1208,12 @@
|
||||
//! )?;
|
||||
//!
|
||||
//! // 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 ...
|
||||
//! # let password_file_bytes = ServerRegistration::<Default>::finish(client_registration_finish_result.message).serialize();
|
||||
//! # let client_login_start_result = ClientLogin::<Default>::start(
|
||||
//! # &mut OsRng,
|
||||
//! # &mut UnwrapErr(SysRng),
|
||||
//! # b"password",
|
||||
//! # )?;
|
||||
//! # let password_file = ServerRegistration::<Default>::deserialize(&password_file_bytes)?;
|
||||
@@ -1231,20 +1250,20 @@
|
||||
//! can be used.
|
||||
//! ```
|
||||
//! # use generic_array::GenericArray;
|
||||
//! use opaque_ke::ksf::Ksf;
|
||||
//! use opaque_vx::ksf::Ksf;
|
||||
//!
|
||||
//! #[derive(Default)]
|
||||
//! struct CustomKsf(scrypt::Params);
|
||||
//!
|
||||
//! // The Ksf trait must be implemented to be used in the ciphersuite.
|
||||
//! impl Ksf for CustomKsf {
|
||||
//! fn hash<L: generic_array::ArrayLength<u8>>(
|
||||
//! fn hash<L: generic_array::ArrayLength>(
|
||||
//! &self,
|
||||
//! 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();
|
||||
//! scrypt::scrypt(&input, &[], &self.0, &mut output)
|
||||
//! .map_err(|_| opaque_ke::errors::InternalError::KsfError)?;
|
||||
//! .map_err(|_| opaque_vx::errors::InternalError::KsfError)?;
|
||||
//!
|
||||
//! Ok(output)
|
||||
//! }
|
||||
@@ -1255,37 +1274,38 @@
|
||||
//! used by the KSF during registration and login. This can be especially
|
||||
//! helpful if the `Ksf` trait is already implemented.
|
||||
//! ```
|
||||
//! # use opaque_ke::CipherSuite;
|
||||
//! # use opaque_ke::ClientRegistration;
|
||||
//! # use opaque_ke::ClientRegistrationFinishParameters;
|
||||
//! # use opaque_ke::ServerSetup;
|
||||
//! # use opaque_ke::errors::ProtocolError;
|
||||
//! # use rand::rngs::OsRng;
|
||||
//! # use rand::RngCore;
|
||||
//! # use opaque_vx::CipherSuite;
|
||||
//! # use opaque_vx::ClientRegistration;
|
||||
//! # use opaque_vx::ClientRegistrationFinishParameters;
|
||||
//! # use opaque_vx::ServerSetup;
|
||||
//! # use opaque_vx::errors::ProtocolError;
|
||||
//! # use rand::rngs::SysRng;
|
||||
//! # use rand::Rng;
|
||||
//! # use rand_core::UnwrapErr;
|
||||
//! # use std::default::Default;
|
||||
//! # #[cfg(feature = "argon2")]
|
||||
//! # {
|
||||
//! # struct DefaultCipherSuite;
|
||||
//! # #[cfg(feature = "ristretto255")]
|
||||
//! # impl CipherSuite for DefaultCipherSuite {
|
||||
//! # type OprfCs = opaque_ke::Ristretto255;
|
||||
//! # type KeyExchange = opaque_ke::TripleDh<opaque_ke::Ristretto255, sha2::Sha512>;
|
||||
//! # type OprfCs = opaque_vx::Ristretto255;
|
||||
//! # type KeyExchange = opaque_vx::TripleDh<opaque_vx::Ristretto255, sha2::Sha512>;
|
||||
//! # type Ksf = argon2::Argon2<'static>;
|
||||
//! # }
|
||||
//! # #[cfg(not(feature = "ristretto255"))]
|
||||
//! # impl CipherSuite for DefaultCipherSuite {
|
||||
//! # 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>;
|
||||
//! # }
|
||||
//! #
|
||||
//! # let password = b"password";
|
||||
//! # let mut rng = OsRng;
|
||||
//! # let mut rng = UnwrapErr(SysRng);
|
||||
//! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
|
||||
//! # let mut client_rng = OsRng;
|
||||
//! # let mut client_rng = UnwrapErr(SysRng);
|
||||
//! # let client_registration_start_result =
|
||||
//! # ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?;
|
||||
//! # use opaque_ke::ServerRegistration;
|
||||
//! # use opaque_vx::ServerRegistration;
|
||||
//! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
|
||||
//! # &server_setup,
|
||||
//! # client_registration_start_result.message,
|
||||
@@ -1384,6 +1404,7 @@ mod tests;
|
||||
#[cfg(feature = "argon2")]
|
||||
pub use argon2;
|
||||
pub use generic_array;
|
||||
pub use hybrid_array;
|
||||
#[cfg(feature = "kem")]
|
||||
pub use ml_kem;
|
||||
pub use rand;
|
||||
|
||||
+57
-39
@@ -15,7 +15,8 @@ use digest::Output;
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{Sum, Unsigned};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hybrid_array::Array;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use voprf::{BlindedElement, BlindedElementLen, EvaluationElement, EvaluationElementLen};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
@@ -50,7 +51,7 @@ use crate::serialization::SliceExt;
|
||||
#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement<CS::OprfCs>)]
|
||||
pub struct RegistrationRequest<CS: CipherSuite> {
|
||||
/// 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
|
||||
@@ -64,10 +65,11 @@ pub struct RegistrationRequest<CS: CipherSuite> {
|
||||
))
|
||||
)]
|
||||
#[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> {
|
||||
/// 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
|
||||
pub(crate) server_s_pk: PublicKey<KeGroup<CS>>,
|
||||
}
|
||||
@@ -111,7 +113,7 @@ pub struct RegistrationUpload<CS: CipherSuite> {
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message,
|
||||
)]
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -136,7 +138,7 @@ pub struct CredentialRequest<CS: CipherSuite> {
|
||||
)]
|
||||
pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> {
|
||||
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) masked_response: MaskedResponse<CS>,
|
||||
#[cfg(test)]
|
||||
@@ -184,12 +186,12 @@ impl<CS: CipherSuite, SK: Clone> ServerLoginBuilder<'_, CS, SK> {
|
||||
#[derive_where(Clone)]
|
||||
#[derive_where(
|
||||
Debug, Eq, Hash, PartialEq;
|
||||
voprf::EvaluationElement<CS::OprfCs>,
|
||||
EvaluationElement<CS::OprfCs>,
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message,
|
||||
)]
|
||||
pub struct CredentialResponse<CS: CipherSuite> {
|
||||
/// 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) masked_response: MaskedResponse<CS>,
|
||||
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> {
|
||||
/// Only used for testing purposes
|
||||
#[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()
|
||||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
|
||||
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>>
|
||||
where
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen> + ArrayLength,
|
||||
RegistrationResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value())
|
||||
.concat(self.server_s_pk.serialize())
|
||||
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
|
||||
self.evaluation_element.value(),
|
||||
));
|
||||
|
||||
elem.concat(self.server_s_pk.serialize())
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
@@ -277,7 +282,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
|
||||
beta: <OprfGroup<CS> as voprf::Group>::Elem,
|
||||
) -> 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(),
|
||||
}
|
||||
}
|
||||
@@ -294,26 +299,29 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
{
|
||||
self.client_s_pk
|
||||
.serialize()
|
||||
.concat(self.masking_key.clone())
|
||||
.concat(self.envelope.serialize())
|
||||
Concat::concat(
|
||||
Concat::concat(
|
||||
self.client_s_pk.serialize(),
|
||||
GenericArray::from_slice(self.masking_key.as_slice()).clone(),
|
||||
),
|
||||
self.envelope.serialize(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
pub fn deserialize(mut input: &[u8]) -> Result<Self, ProtocolError> {
|
||||
Ok(Self {
|
||||
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)?,
|
||||
})
|
||||
}
|
||||
|
||||
// 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,
|
||||
server_setup: &ServerSetup<CS, SK, OS>,
|
||||
) -> Self {
|
||||
@@ -338,11 +346,14 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
|
||||
where
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>> + ArrayLength,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
{
|
||||
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.blinded_element.value())
|
||||
.concat(self.ke1_message.serialize())
|
||||
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
|
||||
self.blinded_element.value(),
|
||||
));
|
||||
|
||||
elem.concat(self.ke1_message.serialize())
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
@@ -372,7 +383,7 @@ impl<CS: CipherSuite> CredentialRequest<CS> {
|
||||
|
||||
/// Only used for testing purposes
|
||||
#[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()
|
||||
}
|
||||
}
|
||||
@@ -390,18 +401,25 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
|
||||
where
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
// 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>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
<OprfGroup<CS> as voprf::Group>::serialize_elem(self.evaluation_element.value())
|
||||
.concat(self.masking_nonce)
|
||||
.concat(self.masked_response.serialize())
|
||||
.concat(self.ke2_message.serialize())
|
||||
let elem = GenericArray::from_ha0_4(<OprfGroup<CS> as voprf::Group>::serialize_elem(
|
||||
self.evaluation_element.value(),
|
||||
));
|
||||
|
||||
Concat::concat(
|
||||
Concat::concat(
|
||||
Concat::concat(elem, self.masking_nonce),
|
||||
self.masked_response.serialize(),
|
||||
),
|
||||
self.ke2_message.serialize(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
@@ -410,7 +428,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Deserialize,
|
||||
{
|
||||
let evaluation_element = EvaluationElement::deserialize(input)?;
|
||||
input = &input[voprf::EvaluationElementLen::<CS::OprfCs>::USIZE..];
|
||||
input = &input[EvaluationElementLen::<CS::OprfCs>::USIZE..];
|
||||
|
||||
Ok(Self {
|
||||
evaluation_element,
|
||||
@@ -438,7 +456,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
|
||||
beta: <OprfGroup<CS> as voprf::Group>::Elem,
|
||||
) -> Self {
|
||||
Self {
|
||||
evaluation_element: voprf::EvaluationElement::from_value_unchecked(beta),
|
||||
evaluation_element: EvaluationElement::from_value_unchecked(beta),
|
||||
masking_nonce: self.masking_nonce,
|
||||
masked_response: self.masked_response.clone(),
|
||||
ke2_message: self.ke2_message.clone(),
|
||||
|
||||
+74
-66
@@ -8,15 +8,14 @@
|
||||
|
||||
//! Provides the main OPAQUE API
|
||||
|
||||
use core::ops::{Add, Deref};
|
||||
|
||||
use core::ops::Add;
|
||||
use derive_where::derive_where;
|
||||
use digest::Output;
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::{Sum, Unsigned};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hkdf::{Hkdf, HkdfExtract};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use hkdf::Hkdf;
|
||||
use hkdf::SimpleHkdfExtract as HkdfExtract;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use subtle::{Choice, ConstantTimeEq, CtOption};
|
||||
use voprf::{BlindedElement, Group as _, OprfClient, OprfClientLen};
|
||||
use zeroize::Zeroizing;
|
||||
@@ -36,7 +35,7 @@ use crate::keypair::{
|
||||
};
|
||||
use crate::ksf::Ksf;
|
||||
use crate::messages::{CredentialRequestLen, RegistrationUploadLen};
|
||||
use crate::serialization::{GenericArrayExt, SliceExt};
|
||||
use crate::serialization::{ConcatExt, GenericArrayExt, SliceExt};
|
||||
use crate::{
|
||||
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
|
||||
RegistrationResponse, RegistrationUpload, ServerLoginBuilder,
|
||||
@@ -70,7 +69,8 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair";
|
||||
))
|
||||
)]
|
||||
#[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<
|
||||
CS: CipherSuite,
|
||||
SK: Clone = PrivateKey<KeGroup<CS>>,
|
||||
@@ -94,8 +94,8 @@ pub struct ServerSetup<
|
||||
voprf::BlindedElement<CS::OprfCs>,
|
||||
)]
|
||||
pub struct ClientRegistration<CS: CipherSuite> {
|
||||
pub(crate) oprf_client: voprf::OprfClient<CS::OprfCs>,
|
||||
pub(crate) blinded_element: voprf::BlindedElement<CS::OprfCs>,
|
||||
pub(crate) oprf_client: OprfClient<CS::OprfCs>,
|
||||
pub(crate) blinded_element: BlindedElement<CS::OprfCs>,
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
)]
|
||||
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) credential_request: CredentialRequest<CS>,
|
||||
}
|
||||
@@ -160,7 +160,7 @@ pub struct ServerLogin<CS: CipherSuite> {
|
||||
|
||||
impl<CS: CipherSuite> ServerSetup<CS, PrivateKey<KeGroup<CS>>> {
|
||||
/// 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);
|
||||
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
|
||||
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
|
||||
/// [`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,
|
||||
keypair: KeyPair<KeGroup<CS>, SK>,
|
||||
oprf_seed: OS,
|
||||
@@ -211,13 +211,13 @@ impl<CS: CipherSuite, SK: Clone, OS: Clone> ServerSetup<CS, SK, OS> {
|
||||
OS: OprfSeedSerialization<OprfHash<CS>, SK::Error>,
|
||||
// ServerSetup: Hash + KeSk + KePk
|
||||
OS::Len: Add<SK::Len>,
|
||||
Sum<OS::Len, SK::Len>: ArrayLength<u8> + Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
ServerSetupLen<CS, SK, OS>: ArrayLength<u8>,
|
||||
Sum<OS::Len, SK::Len>: ArrayLength + Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
ServerSetupLen<CS, SK, OS>: ArrayLength,
|
||||
{
|
||||
self.oprf_seed
|
||||
.serialize()
|
||||
.concat(SK::serialize_key_pair(&self.keypair))
|
||||
.concat(self.dummy_pk.serialize())
|
||||
.cat(SK::serialize_key_pair(&self.keypair))
|
||||
.cat(self.dummy_pk.serialize())
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// instance of [`ServerSetup`]. Instead, use [`ServerSetup::serialize`] and
|
||||
/// [`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,
|
||||
keypair: KeyPair<KeGroup<CS>, SK>,
|
||||
) -> Self {
|
||||
let mut oprf_seed = GenericArray::default();
|
||||
let mut oprf_seed = Output::<OprfHash<CS>>::default();
|
||||
rng.fill_bytes(&mut 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>>
|
||||
where
|
||||
// ClientRegistration: KgSk + KgPk
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
|
||||
ClientRegistrationLen<CS>: ArrayLength<u8>,
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen:
|
||||
Add<<OprfGroup<CS> as voprf::Group>::ElemLen> + ArrayLength,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: ArrayLength,
|
||||
ClientRegistrationLen<CS>: ArrayLength,
|
||||
{
|
||||
self.oprf_client
|
||||
.serialize()
|
||||
.concat(self.blinded_element.serialize())
|
||||
GenericArray::from_ha0_4(self.oprf_client.serialize())
|
||||
.cat(GenericArray::from_ha0_4(self.blinded_element.serialize()))
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// [`ClientRegistration`]
|
||||
pub fn start<R: RngCore + CryptoRng>(
|
||||
pub fn start<R: Rng + CryptoRng>(
|
||||
blinding_factor_rng: &mut R,
|
||||
password: &[u8],
|
||||
) -> Result<ClientRegistrationStartResult<CS>, ProtocolError> {
|
||||
@@ -325,7 +326,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
/// "Unblinds" the server's answer and returns a final message containing
|
||||
/// cryptographic identifiers, to be sent to the server on setup
|
||||
/// finalization
|
||||
pub fn finish<R: CryptoRng + RngCore>(
|
||||
pub fn finish<R: CryptoRng + Rng>(
|
||||
self,
|
||||
rng: &mut R,
|
||||
password: &[u8],
|
||||
@@ -357,7 +358,7 @@ impl<CS: CipherSuite> ClientRegistration<CS> {
|
||||
|
||||
let result = Envelope::<CS>::seal(
|
||||
rng,
|
||||
randomized_pwd_hasher,
|
||||
&randomized_pwd_hasher,
|
||||
®istration_response.server_s_pk,
|
||||
params.identifiers,
|
||||
)?;
|
||||
@@ -390,8 +391,8 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
{
|
||||
self.0.serialize()
|
||||
@@ -449,7 +450,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
|
||||
}
|
||||
|
||||
// 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,
|
||||
server_setup: &ServerSetup<CS, SK, S>,
|
||||
) -> Self {
|
||||
@@ -470,18 +471,17 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
|
||||
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength,
|
||||
{
|
||||
self.oprf_client
|
||||
.serialize()
|
||||
.concat(self.credential_request.serialize())
|
||||
.concat(self.ke1_state.serialize())
|
||||
GenericArray::from_ha0_4(self.oprf_client.serialize())
|
||||
.cat(self.credential_request.serialize())
|
||||
.cat(self.ke1_state.serialize())
|
||||
}
|
||||
|
||||
/// Deserialization from bytes
|
||||
@@ -504,7 +504,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
/// Returns an initial "blinded" password request to send to the server, as
|
||||
/// well as a [`ClientLogin`]
|
||||
pub fn start<R: RngCore + CryptoRng>(
|
||||
pub fn start<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
password: &[u8],
|
||||
) -> 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
|
||||
/// server
|
||||
pub fn finish<R: CryptoRng + RngCore>(
|
||||
pub fn finish<R: CryptoRng + Rng>(
|
||||
self,
|
||||
rng: &mut R,
|
||||
password: &[u8],
|
||||
@@ -570,7 +570,7 @@ impl<CS: CipherSuite> ClientLogin<CS> {
|
||||
|
||||
let opened_envelope = envelope
|
||||
.open(
|
||||
randomized_pwd_hasher,
|
||||
&randomized_pwd_hasher,
|
||||
server_s_pk.clone(),
|
||||
params.identifiers,
|
||||
)
|
||||
@@ -641,7 +641,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
///
|
||||
/// See [`ServerLogin::start()`] for the regular path. Or
|
||||
/// [`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,
|
||||
server_setup: &ServerSetup<CS, SK, OS>,
|
||||
key_material: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
|
||||
@@ -668,7 +668,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
|
||||
let masked_response = mask_response(
|
||||
&record.0.masking_key,
|
||||
masking_nonce.as_slice(),
|
||||
&masking_nonce,
|
||||
server_s_pk,
|
||||
&record.0.envelope,
|
||||
)?;
|
||||
@@ -715,7 +715,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
/// Create a [`ServerLoginBuilder`] to use with a remote private key.
|
||||
///
|
||||
/// 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,
|
||||
server_setup: &ServerSetup<CS, SK>,
|
||||
password_file: Option<ServerRegistration<CS>>,
|
||||
@@ -747,7 +747,7 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
|
||||
let credential_response = CredentialResponse {
|
||||
evaluation_element: builder.evaluation_element.clone(),
|
||||
masking_nonce: *builder.masking_nonce.deref(),
|
||||
masking_nonce: *builder.masking_nonce,
|
||||
masked_response: builder.masked_response.clone(),
|
||||
ke2_message: result.message,
|
||||
};
|
||||
@@ -762,13 +762,13 @@ impl<CS: CipherSuite> ServerLogin<CS> {
|
||||
#[cfg(test)]
|
||||
server_mac_key: result.km2,
|
||||
#[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
|
||||
/// back to the client, as well as a [`ServerLogin`]
|
||||
pub fn start<R: RngCore + CryptoRng>(
|
||||
pub fn start<R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
server_setup: &ServerSetup<CS>,
|
||||
password_file: Option<ServerRegistration<CS>>,
|
||||
@@ -1004,21 +1004,22 @@ pub struct ServerLoginStartResult<CS: CipherSuite> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn get_password_derived_key<CS: CipherSuite>(
|
||||
input: &[u8],
|
||||
oprf_client: voprf::OprfClient<CS::OprfCs>,
|
||||
oprf_client: OprfClient<CS::OprfCs>,
|
||||
evaluation_element: voprf::EvaluationElement<CS::OprfCs>,
|
||||
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_ga = GenericArray::from_ha0_4(oprf_output.clone());
|
||||
|
||||
let hardened_output = if let Some(ksf) = ksf {
|
||||
ksf.hash(oprf_output.clone())
|
||||
ksf.hash(oprf_ga.clone())
|
||||
} else {
|
||||
CS::Ksf::default().hash(oprf_output.clone())
|
||||
CS::Ksf::default().hash(oprf_ga.clone())
|
||||
}
|
||||
.map_err(ProtocolError::from)?;
|
||||
|
||||
let mut hkdf = HkdfExtract::<OprfHash<CS>>::new(None);
|
||||
hkdf.input_ikm(&oprf_output);
|
||||
hkdf.input_ikm(&oprf_ga);
|
||||
hkdf.input_ikm(&hardened_output);
|
||||
Ok(hkdf.finalize())
|
||||
}
|
||||
@@ -1039,13 +1040,9 @@ fn oprf_key_material<CS: CipherSuite>(
|
||||
fn oprf_key_from_key_material<CS: CipherSuite>(
|
||||
input: GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>,
|
||||
) -> Result<GenericArray<u8, <OprfGroup<CS> as voprf::Group>::ScalarLen>, InternalError> {
|
||||
Ok(OprfGroup::<CS>::serialize_scalar(voprf::derive_key::<
|
||||
CS::OprfCs,
|
||||
>(
|
||||
input.as_slice(),
|
||||
&GenericArray::from(*STR_OPAQUE_DERIVE_KEY_PAIR),
|
||||
voprf::Mode::Oprf,
|
||||
)?))
|
||||
Ok(GenericArray::from_ha0_4(OprfGroup::<CS>::serialize_scalar(
|
||||
voprf::derive_key::<CS::OprfCs>(&input, STR_OPAQUE_DERIVE_KEY_PAIR, voprf::Mode::Oprf)?,
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
@@ -1066,19 +1063,28 @@ pub(crate) type MaskedResponseLen<CS: CipherSuite> =
|
||||
|
||||
impl<CS: CipherSuite> MaskedResponse<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> {
|
||||
Ok(Self {
|
||||
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")?,
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
MaskedResponse::deserialize_take(&mut (xor_pad.as_slice()))
|
||||
let mut slice: &[u8] = &xor_pad;
|
||||
|
||||
MaskedResponse::deserialize_take(&mut (slice))
|
||||
}
|
||||
|
||||
fn unmask_response<CS: CipherSuite>(
|
||||
@@ -1124,7 +1132,7 @@ fn unmask_response<CS: CipherSuite>(
|
||||
*x1 ^= x2
|
||||
}
|
||||
|
||||
let mut xor_pad = xor_pad.as_slice();
|
||||
let mut xor_pad: &[u8] = xor_pad.as_ref();
|
||||
let server_s_pk =
|
||||
PublicKey::deserialize_take(&mut xor_pad).map_err(|_| ProtocolError::SerializationError)?;
|
||||
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
|
||||
/// 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.
|
||||
fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
|
||||
fn blind<CS: CipherSuite, R: Rng + CryptoRng>(
|
||||
rng: &mut R,
|
||||
password: &[u8],
|
||||
) -> Result<voprf::OprfClientBlindResult<CS::OprfCs>, voprf::Error> {
|
||||
#[cfg(not(test))]
|
||||
let result = voprf::OprfClient::blind(password, rng)?;
|
||||
let result = OprfClient::blind(password, rng)?;
|
||||
|
||||
#[cfg(test)]
|
||||
let result = {
|
||||
@@ -1152,7 +1160,7 @@ fn blind<CS: CipherSuite, R: RngCore + CryptoRng>(
|
||||
break scalar;
|
||||
}
|
||||
};
|
||||
voprf::OprfClient::deterministic_blind_unchecked(password, blind)?
|
||||
OprfClient::deterministic_blind_unchecked(password, blind)?
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
|
||||
+33
-17
@@ -8,18 +8,16 @@
|
||||
|
||||
use core::ops::Add;
|
||||
|
||||
use crate::errors::ProtocolError;
|
||||
use digest::Update;
|
||||
use generic_array::sequence::Concat;
|
||||
use generic_array::typenum::Sum;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
use crate::errors::ProtocolError;
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
|
||||
// Corresponds to the I2OSP() function from RFC8017
|
||||
pub(crate) fn i2osp<L: ArrayLength<u8>>(
|
||||
input: usize,
|
||||
) -> Result<GenericArray<u8, L>, ProtocolError> {
|
||||
const SIZEOF_USIZE: usize = core::mem::size_of::<usize>();
|
||||
pub(crate) fn i2osp<L: ArrayLength>(input: usize) -> Result<GenericArray<u8, L>, ProtocolError> {
|
||||
const SIZEOF_USIZE: usize = size_of::<usize>();
|
||||
|
||||
// Make sure input fits in output.
|
||||
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
|
||||
#[cfg(test)]
|
||||
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);
|
||||
}
|
||||
|
||||
let mut output_array = [0u8; core::mem::size_of::<usize>()];
|
||||
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
|
||||
let mut output_array = [0u8; size_of::<usize>()];
|
||||
output_array[size_of::<usize>() - input.len()..].copy_from_slice(input);
|
||||
Ok(usize::from_be_bytes(output_array))
|
||||
}
|
||||
|
||||
@@ -69,14 +67,14 @@ impl<T: Update> UpdateExt for T {
|
||||
}
|
||||
|
||||
pub(crate) trait SliceExt {
|
||||
fn take_array<L: ArrayLength<u8>>(
|
||||
fn take_array<L: ArrayLength + ArraySize>(
|
||||
self: &mut &Self,
|
||||
name: &'static str,
|
||||
) -> Result<GenericArray<u8, L>, ProtocolError>;
|
||||
}
|
||||
|
||||
impl SliceExt for [u8] {
|
||||
fn take_array<L: ArrayLength<u8>>(
|
||||
fn take_array<L: ArrayLength + ArraySize>(
|
||||
self: &mut &Self,
|
||||
name: &'static str,
|
||||
) -> Result<GenericArray<u8, L>, ProtocolError> {
|
||||
@@ -90,23 +88,24 @@ impl SliceExt for [u8] {
|
||||
|
||||
let (front, back) = self.split_at(L::USIZE);
|
||||
*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>> {
|
||||
type Output: ArrayLength<u8>;
|
||||
pub(crate) trait GenericArrayExt<O: ArrayLength> {
|
||||
type Output: ArrayLength;
|
||||
|
||||
/// This allows us to concat two [`GenericArray`]s but with `where` bounds
|
||||
/// `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>;
|
||||
}
|
||||
|
||||
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
|
||||
O: Add<L>,
|
||||
Sum<O, L>: ArrayLength<u8>,
|
||||
Sum<O, L>: ArrayLength,
|
||||
{
|
||||
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)]
|
||||
mod tests;
|
||||
|
||||
|
||||
+62
-63
@@ -15,8 +15,9 @@ use generic_array::ArrayLength;
|
||||
use generic_array::typenum::{Sum, Unsigned};
|
||||
use proptest::collection::vec;
|
||||
use proptest::prelude::*;
|
||||
use rand::RngCore;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_core::UnwrapErr;
|
||||
use voprf::Group as _;
|
||||
|
||||
use crate::ciphersuite::{CipherSuite, KeGroup, OprfGroup, OprfHash};
|
||||
@@ -41,7 +42,7 @@ struct TripleDhRistretto255;
|
||||
impl CipherSuite for TripleDhRistretto255 {
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "ristretto255", feature = "curve25519"))]
|
||||
@@ -51,31 +52,31 @@ struct TripleDhCurve25519;
|
||||
impl CipherSuite for TripleDhCurve25519 {
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = TripleDh<Curve25519, sha2::Sha512>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
struct TripleDhP256;
|
||||
|
||||
impl CipherSuite for TripleDhP256 {
|
||||
type OprfCs = ::p256::NistP256;
|
||||
type KeyExchange = TripleDh<::p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type OprfCs = p256::NistP256;
|
||||
type KeyExchange = TripleDh<p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
struct TripleDhP384;
|
||||
|
||||
impl CipherSuite for TripleDhP384 {
|
||||
type OprfCs = ::p384::NistP384;
|
||||
type KeyExchange = TripleDh<::p384::NistP384, sha2::Sha384>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type OprfCs = p384::NistP384;
|
||||
type KeyExchange = TripleDh<p384::NistP384, sha2::Sha384>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
struct TripleDhP521;
|
||||
|
||||
impl CipherSuite for TripleDhP521 {
|
||||
type OprfCs = ::p521::NistP521;
|
||||
type KeyExchange = TripleDh<::p521::NistP521, sha2::Sha512>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type OprfCs = p521::NistP521;
|
||||
type KeyExchange = TripleDh<p521::NistP521, sha2::Sha512>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecdsa")]
|
||||
@@ -83,10 +84,9 @@ struct SigmaIP256;
|
||||
|
||||
#[cfg(feature = "ecdsa")]
|
||||
impl CipherSuite for SigmaIP256 {
|
||||
type OprfCs = ::p256::NistP256;
|
||||
type KeyExchange =
|
||||
SigmaI<Ecdsa<::p256::NistP256, sha2::Sha256>, ::p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type OprfCs = p256::NistP256;
|
||||
type KeyExchange = SigmaI<Ecdsa<p256::NistP256, sha2::Sha256>, p256::NistP256, sha2::Sha256>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecdsa")]
|
||||
@@ -94,10 +94,9 @@ struct SigmaIP384;
|
||||
|
||||
#[cfg(feature = "ecdsa")]
|
||||
impl CipherSuite for SigmaIP384 {
|
||||
type OprfCs = ::p384::NistP384;
|
||||
type KeyExchange =
|
||||
SigmaI<Ecdsa<::p384::NistP384, sha2::Sha384>, ::p384::NistP384, sha2::Sha384>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type OprfCs = p384::NistP384;
|
||||
type KeyExchange = SigmaI<Ecdsa<p384::NistP384, sha2::Sha384>, p384::NistP384, sha2::Sha384>;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "ristretto255", feature = "ed25519",))]
|
||||
@@ -107,7 +106,7 @@ struct SigmaIEd25519;
|
||||
impl CipherSuite for SigmaIEd25519 {
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = SigmaI<PureEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "ristretto255", feature = "ed25519"))]
|
||||
@@ -117,19 +116,19 @@ struct SigmaIEd25519Ph;
|
||||
impl CipherSuite for SigmaIEd25519Ph {
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = SigmaI<HashEddsa<Ed25519>, Ristretto255, sha2::Sha512>;
|
||||
type Ksf = crate::ksf::Identity;
|
||||
type Ksf = ksf::Identity;
|
||||
}
|
||||
|
||||
#[cfg(feature = "ecdsa")]
|
||||
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);
|
||||
KeGroup::<CS>::public_key(&sk)
|
||||
}
|
||||
|
||||
fn random_element<CS: CipherSuite>() -> <OprfGroup<CS> as voprf::Group>::Elem {
|
||||
let mut rng = OsRng;
|
||||
let scalar = OprfGroup::<CS>::random_scalar(&mut rng);
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let scalar = OprfGroup::<CS>::random_scalar(&mut rng).unwrap();
|
||||
OprfGroup::<CS>::base_elem() * &scalar
|
||||
}
|
||||
|
||||
@@ -139,10 +138,10 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
// ClientRegistration: KgSk + KgPk
|
||||
<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 mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
|
||||
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
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
{
|
||||
// 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();
|
||||
rng.fill_bytes(&mut masking_key);
|
||||
|
||||
@@ -287,11 +286,11 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<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 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 pubkey_bytes = skp.public().serialize();
|
||||
|
||||
@@ -345,10 +344,10 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let skp = KeyPair::<KeGroup<CS>>::derive_random(&mut rng);
|
||||
let pubkey_bytes = skp.public().serialize();
|
||||
|
||||
@@ -360,15 +359,15 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> {
|
||||
let mut masking_key = Output::<OprfHash<CS>>::default();
|
||||
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(
|
||||
randomized_pwd_hasher,
|
||||
&randomized_pwd_hasher,
|
||||
nonce.into(),
|
||||
[pubkey_bytes.as_slice()].into_iter(),
|
||||
InnerEnvelopeMode::Internal,
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
let envelope_bytes = envelope.serialize();
|
||||
|
||||
let mut input = Vec::new();
|
||||
@@ -409,9 +408,9 @@ fn triple_dh_credential_request_roundtrip() -> Result<(), ProtocolError> {
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Deserialize + Serialize,
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<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_bytes = OprfGroup::<CS>::serialize_elem(alpha);
|
||||
|
||||
@@ -466,17 +465,17 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> {
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
let elem = random_element::<CS>();
|
||||
let elem_bytes = OprfGroup::<CS>::serialize_elem(elem);
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
|
||||
let mut masking_nonce = [0u8; 32];
|
||||
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(&ke2m);
|
||||
|
||||
let l2 = CredentialResponse::<CS>::deserialize(&input).unwrap();
|
||||
let l2 = CredentialResponse::<CS>::deserialize(&input)?;
|
||||
let l2_bytes = l2.serialize();
|
||||
assert_eq!(input, *l2_bytes);
|
||||
|
||||
@@ -550,17 +549,17 @@ fn sigma_i_ecdsa_credential_response_roundtrip() -> Result<(), ProtocolError> {
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
let pt = random_point::<CS>();
|
||||
let pt_bytes = KeGroup::<CS>::serialize_pk(&pt);
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
|
||||
let mut masking_nonce = [0u8; 32];
|
||||
rng.fill_bytes(&mut masking_nonce);
|
||||
@@ -630,7 +629,7 @@ fn triple_dh_credential_finalization_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let mut mac = Output::<OprfHash<CS>>::default();
|
||||
rng.fill_bytes(&mut mac);
|
||||
|
||||
@@ -661,7 +660,7 @@ fn sigma_i_ecdsa_credential_finalization_roundtrip() -> Result<(), ProtocolError
|
||||
where
|
||||
<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 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
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
|
||||
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength,
|
||||
{
|
||||
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 mut client_nonce = [0; NonceLen::USIZE];
|
||||
@@ -762,7 +761,7 @@ fn triple_dh_ke1_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<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 mut client_nonce = vec![0u8; NonceLen::USIZE];
|
||||
@@ -798,7 +797,7 @@ fn triple_dh_ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<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 mut mac = Output::<OprfHash<CS>>::default();
|
||||
@@ -839,7 +838,7 @@ fn sigma_i_ecdsa_ke2_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<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 mut mac = Output::<OprfHash<CS>>::default();
|
||||
@@ -878,7 +877,7 @@ fn triple_dh_ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<CS::KeyExchange as KeyExchange>::KE3Message: Deserialize + Serialize,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
let mut mac = Output::<OprfHash<CS>>::default();
|
||||
rng.fill_bytes(&mut mac);
|
||||
|
||||
@@ -910,7 +909,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
where
|
||||
<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 s = KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut rng));
|
||||
let mut mac = Output::<OprfHash<CS>>::default();
|
||||
@@ -934,7 +933,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> {
|
||||
|
||||
proptest! {
|
||||
#[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};
|
||||
|
||||
let input = os2ip(&bytes).unwrap();
|
||||
|
||||
+70
-80
@@ -19,8 +19,9 @@ use generic_array::{ArrayLength, GenericArray};
|
||||
#[cfg(feature = "kem")]
|
||||
use ml_kem::MlKem768;
|
||||
use rand::SeedableRng;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::rngs::SysRng;
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use rand_core::UnwrapErr;
|
||||
use serde_json::Value;
|
||||
use subtle::ConstantTimeEq;
|
||||
use voprf::Group as _;
|
||||
@@ -42,6 +43,7 @@ use crate::messages::{
|
||||
RegistrationResponseLen, RegistrationUploadLen,
|
||||
};
|
||||
use crate::opaque::*;
|
||||
use crate::tests::decode;
|
||||
use crate::tests::mock_rng::CycleRng;
|
||||
use crate::*;
|
||||
|
||||
@@ -261,10 +263,6 @@ pub struct TestVectorParameters {
|
||||
|
||||
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 {
|
||||
TestVectorParameters {
|
||||
client_s_pk: decode(values, "client_s_pk").unwrap(),
|
||||
@@ -521,37 +519,37 @@ where
|
||||
<CS::KeyExchange as KeyExchange>::KE3Message: Serialize,
|
||||
// ClientRegistration: KgSk + KgPk
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<<OprfGroup<CS> as voprf::Group>::ElemLen>,
|
||||
ClientRegistrationLen<CS>: ArrayLength<u8>,
|
||||
ClientRegistrationLen<CS>: ArrayLength,
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||
RegistrationResponseLen<CS>: ArrayLength,
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
|
||||
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength,
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
use rand::RngCore;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::keypair::KeyPair;
|
||||
|
||||
@@ -588,20 +586,19 @@ where
|
||||
let dummy_client_pk = dummy_client_pk.serialize();
|
||||
let server_setup = ServerSetup::<CS>::deserialize(
|
||||
&[
|
||||
oprf_seed.as_ref(),
|
||||
&server_s_kp.private().serialize(),
|
||||
&dummy_client_pk,
|
||||
oprf_seed.as_slice(),
|
||||
server_s_kp.private().serialize().as_slice(),
|
||||
dummy_client_pk.as_slice(),
|
||||
]
|
||||
.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 mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec());
|
||||
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(
|
||||
client_registration_start_result
|
||||
.state
|
||||
@@ -620,8 +617,8 @@ where
|
||||
&server_setup,
|
||||
client_registration_start_result.message,
|
||||
credential_identifier,
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
|
||||
let registration_response_bytes = server_registration_start_result.message.serialize();
|
||||
|
||||
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);
|
||||
|
||||
let mut finish_registration_rng = CycleRng::new(client_s_sk_and_nonce);
|
||||
let client_registration_finish_result = client_registration_start_result
|
||||
.state
|
||||
.finish(
|
||||
&mut finish_registration_rng,
|
||||
password,
|
||||
server_registration_start_result.message,
|
||||
ClientRegistrationFinishParameters::new(
|
||||
Identifiers {
|
||||
client: Some(id_u),
|
||||
server: Some(id_s),
|
||||
},
|
||||
None,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let client_registration_finish_result = client_registration_start_result.state.finish(
|
||||
&mut finish_registration_rng,
|
||||
password,
|
||||
server_registration_start_result.message,
|
||||
ClientRegistrationFinishParameters::new(
|
||||
Identifiers {
|
||||
client: Some(id_u),
|
||||
server: Some(id_s),
|
||||
},
|
||||
None,
|
||||
),
|
||||
)?;
|
||||
let registration_upload_bytes = client_registration_finish_result.message.serialize();
|
||||
|
||||
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 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 client_login_state = client_login_start_result.state.serialize().to_vec();
|
||||
|
||||
@@ -683,27 +677,23 @@ where
|
||||
server: Some(id_s),
|
||||
},
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
let credential_response_bytes = server_login_start_result.message.serialize();
|
||||
let server_login_state = server_login_start_result.state.serialize();
|
||||
|
||||
let client_login_finish_result = client_login_start_result
|
||||
.state
|
||||
.finish(
|
||||
&mut CycleRng::new(client_sig_rng.to_vec()),
|
||||
password,
|
||||
server_login_start_result.message,
|
||||
ClientLoginFinishParameters::new(
|
||||
Some(context),
|
||||
Identifiers {
|
||||
client: Some(id_u),
|
||||
server: Some(id_s),
|
||||
},
|
||||
None,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let client_login_finish_result = client_login_start_result.state.finish(
|
||||
&mut CycleRng::new(client_sig_rng.to_vec()),
|
||||
password,
|
||||
server_login_start_result.message,
|
||||
ClientLoginFinishParameters::new(
|
||||
Some(context),
|
||||
Identifiers {
|
||||
client: Some(id_u),
|
||||
server: Some(id_s),
|
||||
},
|
||||
None,
|
||||
),
|
||||
)?;
|
||||
let credential_finalization_bytes = client_login_finish_result.message.serialize();
|
||||
|
||||
Ok(TestVectorParameters {
|
||||
@@ -787,7 +777,7 @@ fn test_registration_request() -> Result<(), ProtocolError> {
|
||||
where
|
||||
// ClientRegistration: KgSk + KgPk
|
||||
<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 mut rng = CycleRng::new(parameters.blinding_factor.to_vec());
|
||||
@@ -821,15 +811,15 @@ fn test_serialization() -> Result<(), ProtocolError> {
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<CS>::start(&mut rng, ¶meters.password)?;
|
||||
|
||||
// Test the bincode serialization (binary).
|
||||
// Test the postcard serialization (binary).
|
||||
let registration_request =
|
||||
bincode::serialize(&client_registration_start_result.message).unwrap();
|
||||
postcard::to_allocvec(&client_registration_start_result.message).unwrap();
|
||||
assert_eq!(
|
||||
registration_request.len(),
|
||||
RegistrationRequestLen::<CS>::USIZE
|
||||
);
|
||||
let registration_request: RegistrationRequest<CS> =
|
||||
bincode::deserialize(®istration_request).unwrap();
|
||||
postcard::from_bytes(®istration_request).unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(client_registration_start_result.message.serialize()),
|
||||
hex::encode(registration_request.serialize()),
|
||||
@@ -852,7 +842,7 @@ fn test_registration_response() -> Result<(), ProtocolError> {
|
||||
where
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||
RegistrationResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
let parameters = populate_test_vectors(
|
||||
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
|
||||
@@ -894,8 +884,8 @@ fn test_registration_upload() -> Result<(), ProtocolError> {
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
{
|
||||
let parameters = populate_test_vectors(
|
||||
&serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?,
|
||||
@@ -945,8 +935,8 @@ fn test_password_file() -> Result<(), ProtocolError> {
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
{
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
|
||||
@@ -977,13 +967,13 @@ fn test_credential_request() -> Result<(), ProtocolError> {
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
// ClientLogin: KgSk + CredentialRequest + Ke1State
|
||||
<OprfGroup<CS> as voprf::Group>::ScalarLen: Add<CredentialRequestLen<CS>>,
|
||||
<CS::KeyExchange as KeyExchange>::KE1State: Serialize,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ScalarLen, CredentialRequestLen<CS>>:
|
||||
ArrayLength<u8> + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<Ke1StateLen<CS>>,
|
||||
ClientLoginLen<CS>: ArrayLength,
|
||||
{
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
|
||||
|
||||
@@ -1024,12 +1014,12 @@ fn test_credential_response() -> Result<(), ProtocolError> {
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap());
|
||||
|
||||
@@ -1182,8 +1172,8 @@ fn test_complete_flow<CS: CipherSuite>(
|
||||
login_password: &[u8],
|
||||
) -> Result<(), ProtocolError> {
|
||||
let credential_identifier = b"credentialIdentifier";
|
||||
let mut client_rng = OsRng;
|
||||
let mut server_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let mut server_rng = UnwrapErr(SysRng);
|
||||
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<CS>::start(&mut client_rng, registration_password)?;
|
||||
@@ -1330,8 +1320,8 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> {
|
||||
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
|
||||
let credential_identifier = b"credentialIdentifier";
|
||||
let password = b"password";
|
||||
let mut client_rng = OsRng;
|
||||
let mut server_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let mut server_rng = UnwrapErr(SysRng);
|
||||
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<CS>::start(&mut client_rng, password)?;
|
||||
@@ -1377,8 +1367,8 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> {
|
||||
fn inner<CS: CipherSuite>(_test_vector: &str) -> Result<(), ProtocolError> {
|
||||
let credential_identifier = b"credentialIdentifier";
|
||||
let password = b"password";
|
||||
let mut client_rng = OsRng;
|
||||
let mut server_rng = OsRng;
|
||||
let mut client_rng = UnwrapErr(SysRng);
|
||||
let mut server_rng = UnwrapErr(SysRng);
|
||||
let server_setup = ServerSetup::<CS>::new(&mut server_rng);
|
||||
let client_registration_start_result =
|
||||
ClientRegistration::<CS>::start(&mut client_rng, password)?;
|
||||
|
||||
+24
-17
@@ -9,9 +9,10 @@
|
||||
use core::cmp::min;
|
||||
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)
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -38,29 +39,35 @@ fn rotate_left<T>(data: &mut [T], steps: usize) {
|
||||
data.reverse();
|
||||
}
|
||||
|
||||
impl RngCore for CycleRng {
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
unimplemented!()
|
||||
impl TryRng for CycleRng {
|
||||
type Error = Infallible;
|
||||
|
||||
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 next_u64(&mut self) -> u64 {
|
||||
unimplemented!()
|
||||
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||
let mut buf = [0u8; 8];
|
||||
|
||||
self.try_fill_bytes(&mut buf)?;
|
||||
|
||||
Ok(u64::from_le_bytes(buf))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
|
||||
let len = min(self.v.len(), dest.len());
|
||||
dest[..len].copy_from_slice(&self.v[..len]);
|
||||
rotate_left(&mut self.v, len);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
self.fill_bytes(dest);
|
||||
dest[..len].copy_from_slice(&self.v[..len]);
|
||||
|
||||
rotate_left(&mut self.v, len);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// This is meant for testing only
|
||||
impl CryptoRng for CycleRng {}
|
||||
impl TryCryptoRng for CycleRng {}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
// of this source tree. You may select, at your option, one of the above-listed
|
||||
// licenses.
|
||||
|
||||
use serde_json::Value;
|
||||
use std::vec::Vec;
|
||||
|
||||
mod full_test;
|
||||
#[rustfmt::skip]
|
||||
#[allow(dead_code)]
|
||||
@@ -14,3 +17,7 @@ pub mod mock_rng;
|
||||
mod parser;
|
||||
mod rfc9807_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
@@ -15,20 +15,18 @@ pub(crate) fn rfc_to_json(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 chunks: Vec<&str> = re.split(input).collect();
|
||||
|
||||
let mut count = 1;
|
||||
for caps in re.captures_iter(input) {
|
||||
for (count, caps) in (1..).zip(re.captures_iter(input)) {
|
||||
let vector_type = format!(
|
||||
"\"{}\": [\n {} \n]",
|
||||
&caps["type"].trim(),
|
||||
parse_ciphersuites(chunks[count])
|
||||
);
|
||||
vector_types.push(vector_type);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
vector_types.join(",\n")
|
||||
@@ -36,15 +34,14 @@ fn parse_vector_types(input: &str) -> String {
|
||||
|
||||
fn parse_ciphersuites(input: &str) -> String {
|
||||
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();
|
||||
let mut ciphersuites = vec![];
|
||||
|
||||
let chunks: Vec<&str> = re.split(input).collect();
|
||||
|
||||
let mut count = 1;
|
||||
for caps in re.captures_iter(input) {
|
||||
for (count, caps) in (1..).zip(re.captures_iter(input)) {
|
||||
let ciphersuite = format!(
|
||||
"{{ \"{}, {}\": {{ {} }} }}",
|
||||
&caps["oprf"],
|
||||
@@ -52,7 +49,6 @@ fn parse_ciphersuites(input: &str) -> String {
|
||||
parse_params(chunks[count])
|
||||
);
|
||||
ciphersuites.push(ciphersuite);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
ciphersuites.join(",\n")
|
||||
|
||||
@@ -10,13 +10,6 @@ use core::ops::Add;
|
||||
use std::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::envelope::EnvelopeLen;
|
||||
use crate::errors::*;
|
||||
@@ -30,8 +23,16 @@ use crate::messages::{
|
||||
RegistrationResponseLen, RegistrationUploadLen,
|
||||
};
|
||||
use crate::opaque::*;
|
||||
use crate::tests::decode;
|
||||
use crate::tests::mock_rng::CycleRng;
|
||||
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)]
|
||||
#[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 {
|
||||
let mut rng = OsRng;
|
||||
let mut rng = UnwrapErr(SysRng);
|
||||
|
||||
OpaqueTestVectorParameters {
|
||||
dummy_public_key: {
|
||||
match decode(values, "client_public_key") {
|
||||
Some(value) => value,
|
||||
None => KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut OsRng)).to_vec(),
|
||||
}
|
||||
decode(values, "client_public_key").unwrap_or_else(|| {
|
||||
KeGroup::<CS>::serialize_sk(&KeGroup::<CS>::random_sk(&mut UnwrapErr(SysRng)))
|
||||
.to_vec()
|
||||
})
|
||||
},
|
||||
dummy_masking_key: {
|
||||
match decode(values, "masking_key") {
|
||||
@@ -151,8 +148,8 @@ where
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
{
|
||||
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())
|
||||
.expect("Could not parse json");
|
||||
|
||||
std::eprintln!("{}", serde_json::to_string_pretty(&rfc).unwrap());
|
||||
|
||||
#[cfg(feature = "ristretto255")]
|
||||
{
|
||||
struct Ristretto255Sha512NoKsf;
|
||||
impl CipherSuite for Ristretto255Sha512NoKsf {
|
||||
type OprfCs = crate::Ristretto255;
|
||||
type KeyExchange = TripleDh<crate::Ristretto255, sha2::Sha512>;
|
||||
type OprfCs = Ristretto255;
|
||||
type KeyExchange = TripleDh<Ristretto255, sha2::Sha512>;
|
||||
type Ksf = Identity;
|
||||
}
|
||||
|
||||
@@ -331,7 +330,7 @@ fn test_registration_response<CS: CipherSuite>(
|
||||
where
|
||||
// RegistrationResponse: KgPk + KePk
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<<KeGroup<CS> as Group>::PkLen>,
|
||||
RegistrationResponseLen<CS>: ArrayLength<u8>,
|
||||
RegistrationResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let server_setup = ServerSetup::<CS>::deserialize(
|
||||
@@ -370,8 +369,8 @@ where
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let mut rng = CycleRng::new(parameters.blind_registration.to_vec());
|
||||
@@ -417,7 +416,7 @@ where
|
||||
// CredentialRequest: KgPk + Ke1Message
|
||||
<CS::KeyExchange as KeyExchange>::KE1Message: Serialize,
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<Ke1MessageLen<CS>>,
|
||||
CredentialRequestLen<CS>: ArrayLength<u8>,
|
||||
CredentialRequestLen<CS>: ArrayLength,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let client_login_start = [
|
||||
@@ -444,18 +443,18 @@ where
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let server_setup = ServerSetup::<CS>::deserialize(
|
||||
@@ -530,7 +529,7 @@ where
|
||||
ClientLogin::<CS>::start(&mut client_login_start_rng, ¶meters.password)?;
|
||||
|
||||
let client_login_finish_result = client_login_start_result.state.finish(
|
||||
&mut OsRng,
|
||||
&mut UnwrapErr(SysRng),
|
||||
¶meters.password,
|
||||
CredentialResponse::<CS>::deserialize(¶meters.KE2)?,
|
||||
ClientLoginFinishParameters::new(
|
||||
@@ -576,8 +575,8 @@ where
|
||||
// RegistrationUpload: (KePk + Hash) + Envelope
|
||||
<KeGroup<CS> as Group>::PkLen: Add<OutputSize<OprfHash<CS>>>,
|
||||
Sum<<KeGroup<CS> as Group>::PkLen, OutputSize<OprfHash<CS>>>:
|
||||
ArrayLength<u8> + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<EnvelopeLen<CS>>,
|
||||
RegistrationUploadLen<CS>: ArrayLength,
|
||||
// ServerRegistration = RegistrationUpload
|
||||
{
|
||||
for parameters in tvs {
|
||||
@@ -644,12 +643,12 @@ where
|
||||
// CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse
|
||||
<OprfGroup<CS> as voprf::Group>::ElemLen: Add<NonceLen>,
|
||||
Sum<<OprfGroup<CS> as voprf::Group>::ElemLen, NonceLen>:
|
||||
ArrayLength<u8> + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength<u8>,
|
||||
ArrayLength + Add<MaskedResponseLen<CS>>,
|
||||
CredentialResponseWithoutKeLen<CS>: ArrayLength,
|
||||
// CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message
|
||||
<CS::KeyExchange as KeyExchange>::KE2Message: Serialize,
|
||||
CredentialResponseWithoutKeLen<CS>: Add<Ke2MessageLen<CS>>,
|
||||
CredentialResponseLen<CS>: ArrayLength<u8>,
|
||||
CredentialResponseLen<CS>: ArrayLength,
|
||||
{
|
||||
for parameters in tvs {
|
||||
let server_setup = ServerSetup::<CS>::deserialize(
|
||||
|
||||
@@ -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
@@ -36,27 +36,27 @@ use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, Tag, ToEncodedPoint};
|
||||
use elliptic_curve::{AffinePoint, CurveArithmetic, FieldBytesSize, Group as _, ProjectivePoint};
|
||||
use generic_array::typenum::Unsigned;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use opaque_ke::key_exchange::KeyExchange;
|
||||
use opaque_ke::key_exchange::group::Group;
|
||||
use opaque_vx::key_exchange::KeyExchange;
|
||||
use opaque_vx::key_exchange::group::Group;
|
||||
#[cfg(all(feature = "ristretto255", feature = "ed25519"))]
|
||||
use opaque_ke::key_exchange::group::ed25519::{self, Ed25519};
|
||||
use opaque_ke::key_exchange::group::elliptic_curve::NonIdentity;
|
||||
use opaque_vx::key_exchange::group::ed25519::{self, Ed25519};
|
||||
use opaque_vx::key_exchange::group::elliptic_curve::NonIdentity;
|
||||
#[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"))]
|
||||
use opaque_ke::key_exchange::sigma_i::pure_eddsa::PureEddsa;
|
||||
use opaque_vx::key_exchange::sigma_i::pure_eddsa::PureEddsa;
|
||||
#[cfg(feature = "ecdsa")]
|
||||
use opaque_ke::key_exchange::sigma_i::{CachedMessage, HashOutput, Message, SigmaI};
|
||||
use opaque_ke::key_exchange::tripledh::TripleDh;
|
||||
use opaque_ke::keypair::{KeyPair, PublicKey};
|
||||
use opaque_ke::ksf::Identity;
|
||||
use opaque_ke::{
|
||||
use opaque_vx::key_exchange::sigma_i::{CachedMessage, HashOutput, Message, SigmaI};
|
||||
use opaque_vx::key_exchange::tripledh::TripleDh;
|
||||
use opaque_vx::keypair::{KeyPair, PublicKey};
|
||||
use opaque_vx::ksf::Identity;
|
||||
use opaque_vx::{
|
||||
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginStartResult,
|
||||
ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationStartResult,
|
||||
ServerLogin, ServerLoginParameters, ServerLoginStartResult, ServerRegistration, ServerSetup,
|
||||
};
|
||||
#[cfg(all(feature = "curve25519", feature = "ristretto255"))]
|
||||
use opaque_ke::{Curve25519, Ristretto255};
|
||||
use opaque_vx::{Curve25519, Ristretto255};
|
||||
use p256::NistP256;
|
||||
use p384::NistP384;
|
||||
use p521::NistP521;
|
||||
|
||||
Reference in New Issue
Block a user