diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..9ff6225 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,156 @@ +name: Rust CI + +on: + push: + branches: + - master + pull_request: + types: [ opened, reopened, synchronize ] + +concurrency: + group: ci-${{ gitea.ref }} + cancel-in-progress: true + +jobs: + fmt: + name: cargo fmt + runs-on: linux_amd64 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - name: Run cargo fmt + run: cargo fmt --all -- --check + + clippy: + name: cargo clippy + runs-on: linux_amd64 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - name: Cache cargo + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-registry- + - name: Run cargo clippy + run: cargo clippy --all-targets --features argon2,std,curve25519,ecdsa,ed25519,kem -- -D warnings + - name: Run cargo doc + run: cargo doc --no-deps --document-private-items --features argon2,std,curve25519,ecdsa,ed25519,kem + env: + RUSTDOCFLAGS: -D warnings + + test: + name: test (${{ matrix.toolchain }} / ${{ matrix.backend_feature || 'no backend' }} / ${{ matrix.frontend_feature || 'no frontend' }}) + runs-on: linux_amd64 + strategy: + fail-fast: false + matrix: + backend_feature: + - "" + - --features ristretto255 + - --features ristretto255,kem + - --features curve25519 + - --features ecdsa + - --features ed25519 + - --features ristretto255,curve25519,ecdsa,ed25519 + frontend_feature: + - "" + - --features argon2 + - --features serde + toolchain: + - stable + - "1.90.0" + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@${{ matrix.toolchain }} + - name: Cache cargo + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-registry- + - name: Run cargo test + run: cargo test --no-default-features ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }} + - name: Run cargo test with std + run: cargo test --no-default-features --features std ${{ matrix.backend_feature }} ${{ matrix.frontend_feature }} + + simple-login-test: + name: test simple_login example + runs-on: linux_amd64 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + - name: Run expect + run: expect -f scripts/simple_login.exp + + digital-locker-test: + name: test digital_locker example + runs-on: linux_amd64 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + - name: Run expect + run: expect -f scripts/digital_locker.exp + + build-no-std: + name: no-std (${{ matrix.target }} / ${{ matrix.backend_feature || 'no backend' }}) + runs-on: linux_amd64 + strategy: + fail-fast: false + matrix: + target: + - wasm32-unknown-unknown + - thumbv6m-none-eabi + backend_feature: + - "" + - ristretto255 + - curve25519 + - ecdsa + - ed25519 + - ristretto255,curve25519,ecdsa,ed25519 + frontend_feature: + - argon2 + - serde + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + - name: Build no-std + run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }},${{ matrix.backend_feature }} + + benches: + name: cargo bench compilation + runs-on: linux_amd64 + strategy: + fail-fast: false + matrix: + backend_feature: + - --features ristretto255 + - --features ristretto255,kem + - "" + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + - name: Run cargo bench --no-run + run: cargo bench --no-default-features ${{ matrix.backend_feature }} --no-run + + audit: + name: cargo audit + runs-on: linux_amd64 + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + - uses: dtolnay/rust-toolchain@stable + - name: Install cargo-audit + run: cargo install cargo-audit + - name: Run cargo audit + run: cargo audit -D warnings \ No newline at end of file diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml new file mode 100644 index 0000000..dd25508 --- /dev/null +++ b/.gitea/workflows/publish.yml @@ -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 }} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0306bec..a74bc9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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.90** +* Renamed crate to `opaque-vx` +* Removed direct `rfc6979` dependency (handled by `ecdsa` internally) +* Removed unstable `rustfmt` configurations for **Rust stable** compatibility +* Removed Facebook-specific contributions (CLA, bounty program) from `CONTRIBUTING.md` +* Removed `v3` to `v4` migration test (no longer relevant for fork) + ## 4.1.0-pre.2 (March 26, 2026) + * 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 = <<::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; - type OldSkLen = <::KeGroup as opaque_ke_3::key_exchange::group::KeGroup>::SkLen; - - let (old_serialied_rest, old_fake_keypair_serialized): ( - GenericArray>, - _, - ) = old_serialized.split(); - - let old_fake_keypair = - KeyPair::<::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::::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 = <<::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; + type OldSkLen = <::KeGroup as opaque_ke_3::key_exchange::group::KeGroup>::SkLen; + + let (old_serialied_rest, old_fake_keypair_serialized): ( + GenericArray>, + _, + ) = old_serialized.split(); + + let old_fake_keypair = + KeyPair::<::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::::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::::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::::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 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index f049d4c..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -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 . 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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 145a05a..b185614 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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: - ## 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 diff --git a/Cargo.toml b/Cargo.toml index a134888..4c08789 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,110 +1,116 @@ [package] -authors = ["Kevin Lewi ", "François Garillot "] -categories = ["no-std"] +authors = [ + "VexaHub Developers", + "Kevin Lewi ", + "François Garillot ", +] +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.90" +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" +bincode-next = { version = "3", features = ["serde", "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" +pastey = "0.2" 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]] diff --git a/README.md b/README.md index d24e595..fa8242d 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,28 @@ -## The OPAQUE key exchange protocol ![Build Status](https://github.com/facebook/opaque-ke/workflows/Rust%20CI/badge.svg) +## The OPAQUE key exchange protocol -[OPAQUE](https://eprint.iacr.org/2018/163.pdf) is an augmented password-authenticated key exchange protocol. It allows a client to authenticate to a server using a password, without ever having to expose the plaintext password to the server. +[OPAQUE](https://eprint.iacr.org/2018/163.pdf) is an augmented password-authenticated key exchange protocol. It allows a +client to authenticate to a server using a password, without ever having to expose the plaintext password to the server. This implementation is based on [RFC 9807](https://datatracker.ietf.org/doc/rfc9807/). +This 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.89** 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 diff --git a/benches/opaque.rs b/benches/opaque.rs index f693521..1968b68 100644 --- a/benches/opaque.rs +++ b/benches/opaque.rs @@ -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; - type Ksf = opaque_ke::ksf::Identity; + type OprfCs = Ristretto255; + type KeyExchange = TripleDh; + type Ksf = ksf::Identity; } #[cfg(not(feature = "ristretto255"))] impl CipherSuite for Default { type OprfCs = p256::NistP256; - type KeyExchange = opaque_ke::TripleDh; - type Ksf = opaque_ke::ksf::Identity; + type KeyExchange = TripleDh; + 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::::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::::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::::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::::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::::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::::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::::new(&mut rng); diff --git a/examples/digital_locker.rs b/examples/digital_locker.rs index 571856c..9f3d634 100644 --- a/examples/digital_locker.rs +++ b/examples/digital_locker.rs @@ -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; - type Ksf = opaque_ke::ksf::Identity; + type OprfCs = opaque_vx::Ristretto255; + type KeyExchange = opaque_vx::TripleDh; + type Ksf = opaque_vx::ksf::Identity; } #[cfg(not(feature = "ristretto255"))] impl CipherSuite for DefaultCipherSuite { type OprfCs = p256::NistP256; - type KeyExchange = opaque_ke::TripleDh; - type Ksf = opaque_ke::ksf::Identity; + type KeyExchange = opaque_vx::TripleDh; + type Ksf = opaque_vx::ksf::Identity; } struct Locker { contents: Vec, - password_file: GenericArray>, + password_file: Vec, } // Given a key and plaintext, produce an AEAD ciphertext along with a nonce fn encrypt(key: &[u8], plaintext: &[u8]) -> Vec { - 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 { - 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::::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 { - let mut client_rng = OsRng; + let mut client_rng = UnwrapErr(SysRng); let client_login_start_result = ClientLogin::::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::::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::::new(&mut rng); let mut rl = Editor::<(), _>::new().unwrap(); diff --git a/examples/simple_login.rs b/examples/simple_login.rs index 7affe74..896150f 100644 --- a/examples/simple_login.rs +++ b/examples/simple_login.rs @@ -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; + type OprfCs = opaque_vx::Ristretto255; + type KeyExchange = opaque_vx::TripleDh; 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; + type KeyExchange = opaque_vx::TripleDh; type Ksf = Argon2<'static>; } @@ -65,8 +65,8 @@ fn account_registration( server_setup: &ServerSetup, username: String, password: String, -) -> GenericArray> { - let mut client_rng = OsRng; +) -> Array> { + let mut client_rng = UnwrapErr(SysRng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, password.as_bytes()) .unwrap(); @@ -100,7 +100,7 @@ fn account_registration( let password_file = ServerRegistration::finish( RegistrationUpload::::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::::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::::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::::new(&mut rng); let mut rl = Editor::<(), _>::new().unwrap(); let mut registered_users = - HashMap::>>::new(); + HashMap::>>::new(); loop { println!( "\nCurrently registered usernames: {:?}\n", diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..510e947 --- /dev/null +++ b/renovate.json @@ -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 +} \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml index faa263a..43d4840 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -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 diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs index 02d0143..3f63674 100644 --- a/src/ciphersuite.rs +++ b/src/ciphersuite.rs @@ -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: Hash, + OprfHash: Hash + EagerHash, as CoreProxy>::Core: ProxyHash, - < as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess, - Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + < as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<< as CoreProxy>::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, // Envelope: Nonce + Hash // MaskedResponse: (Nonce + Hash) + KePk - OutputSize>: Add, - Sum>, NonceLen>: - ArrayLength + Add< as Group>::PkLen>, - MaskedResponseLen: ArrayLength, + OutputSize>: Add + ArrayLength, + Sum>, NonceLen>: ArrayLength + Add< as Group>::PkLen>, + MaskedResponseLen: ArrayLength, + // hybrid-array interop bounds + as voprf::Group>::ScalarLen: ArrayLength, + as voprf::Group>::ElemLen: ArrayLength, { /// A VOPRF ciphersuite, see [`voprf::CipherSuite`]. type OprfCs: voprf::CipherSuite; diff --git a/src/envelope.rs b/src/envelope.rs index 7d61b91..6bf168f 100644 --- a/src/envelope.rs +++ b/src/envelope.rs @@ -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}; @@ -108,9 +107,9 @@ pub(crate) type EnvelopeLen = Sum>, Non impl Envelope { #[allow(clippy::type_complexity)] - pub(crate) fn seal( + pub(crate) fn seal( rng: &mut R, - randomized_pwd_hasher: Hkdf>, + randomized_pwd_hasher: &Hkdf>, server_s_pk: &PublicKey>, ids: Identifiers, ) -> Result, ProtocolError> { @@ -119,7 +118,7 @@ impl Envelope { let (mode, client_s_pk) = ( InnerEnvelopeMode::Internal, - build_inner_envelope_internal::(randomized_pwd_hasher.clone(), nonce)?, + build_inner_envelope_internal::(randomized_pwd_hasher, nonce)?, ); let server_s_pk_bytes = server_s_pk.serialize(); @@ -148,7 +147,7 @@ impl Envelope { /// 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>, + randomized_pwd_hasher: &Hkdf>, nonce: GenericArray, aad: impl Iterator, mode: InnerEnvelopeMode, @@ -163,7 +162,7 @@ impl Envelope { .expand_multi_info(&[&nonce, &STR_EXPORT_KEY], &mut export_key) .map_err(|_| InternalError::HkdfError)?; - let mut hmac = Hmac::>::new_from_slice(&hmac_key) + let mut hmac = SimpleHmac::>::new_from_slice(&hmac_key) .map_err(|_| InternalError::HmacError)?; hmac.update(&nonce); hmac.update_iter(aad); @@ -184,7 +183,7 @@ impl Envelope { pub(crate) fn open<'a>( &self, - randomized_pwd_hasher: Hkdf>, + randomized_pwd_hasher: &Hkdf>, server_s_pk: PublicKey>, optional_ids: Identifiers<'a>, ) -> Result, ProtocolError> { @@ -193,7 +192,7 @@ impl Envelope { return Err(InternalError::IncompatibleEnvelopeModeError.into()); } InnerEnvelopeMode::Internal => { - recover_keys_internal::(randomized_pwd_hasher.clone(), self.nonce)? + recover_keys_internal::(randomized_pwd_hasher, self.nonce)? } }; @@ -222,20 +221,20 @@ impl Envelope { /// if the key and aad used to construct the envelope are the same. pub(crate) fn open_raw<'a>( &self, - randomized_pwd_hasher: Hkdf>, + randomized_pwd_hasher: &Hkdf>, aad: impl Iterator, ) -> Result, InternalError> { let mut hmac_key = Output::>::default(); let mut export_key = Output::>::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::>::new_from_slice(&hmac_key) + let mut hmac = SimpleHmac::>::new_from_slice(&hmac_key) .map_err(|_| InternalError::HmacError)?; hmac.update(&self.nonce); hmac.update_iter(aad); @@ -250,7 +249,7 @@ impl Envelope { Self { mode: InnerEnvelopeMode::Zero, nonce: GenericArray::default(), - hmac: GenericArray::default(), + hmac: GenericArray::default().into_ha0_4(), } } @@ -262,14 +261,17 @@ impl Envelope { } pub(crate) fn serialize(&self) -> GenericArray> { - self.nonce.concat_ext(&self.hmac) + self.nonce + .concat_ext(&GenericArray::from_ha0_4(self.hmac.clone())) } pub(crate) fn deserialize_take(bytes: &mut &[u8]) -> Result { Ok(Self { mode: InnerEnvelopeMode::Internal, nonce: bytes.take_array("nonce")?, - hmac: bytes.take_array("hmac")?, + hmac: bytes + .take_array::>>("hmac")? + .into_ha0_4(), }) } } @@ -277,12 +279,12 @@ impl Envelope { // Helper functions fn build_inner_envelope_internal( - randomized_pwd_hasher: Hkdf>, + randomized_pwd_hasher: &Hkdf>, nonce: GenericArray, ) -> Result>, ProtocolError> { let mut keypair_seed = GenericArray::<_, 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::::derive_scalar(keypair_seed)?); @@ -290,12 +292,12 @@ fn build_inner_envelope_internal( } fn recover_keys_internal( - randomized_pwd_hasher: Hkdf>, + randomized_pwd_hasher: &Hkdf>, nonce: GenericArray, ) -> Result>, ProtocolError> { let mut keypair_seed = GenericArray::<_, 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::::derive_scalar(keypair_seed)?); let client_s_pk = client_s_sk.public_key(); diff --git a/src/errors.rs b/src/errors.rs index d72fbe1..620cfeb 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -141,8 +141,8 @@ impl From for ProtocolError { // 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 From<::core::convert::Infallible> for ProtocolError { - fn from(_: ::core::convert::Infallible) -> Self { +impl From for ProtocolError { + fn from(_: Infallible) -> Self { unreachable!() } } @@ -164,6 +164,7 @@ impl ProtocolError { actual_len, }, Self::ReflectedValueError => ProtocolError::ReflectedValueError, + Self::Custom(infallible) => match infallible {}, } } } diff --git a/src/hash.rs b/src/hash.rs index d4d25a9..548df23 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -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 = <::Core as OutputSizeUser>::OutputSize; /// Trait to simplify requirements for [`Hash`]. pub trait ProxyHash: - HashMarker + FixedOutputCore + BufferKindUser + Default + Clone + HashMarker + FixedOutputCore + BufferKindUser + OutputSizeUser + Default + Clone where - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + ::_BlockSize: IsLess, + Le<::_BlockSize, U256>: NonZero, { } -impl + Default + Clone> - ProxyHash for T +impl< + T: HashMarker + + FixedOutputCore + + BufferKindUser + + OutputSizeUser + + Default + + Clone, +> ProxyHash for T where - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + ::_BlockSize: IsLess, + Le<::_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: pub trait Hash: Default + HashMarker + + Digest + OutputSizeUser> + BlockSizeUser + FixedOutputReset @@ -45,14 +54,16 @@ pub trait Hash: + Clone where ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: generic_array::ArrayLength, { } impl< T: Default + HashMarker + + Digest + OutputSizeUser> + BlockSizeUser + FixedOutputReset @@ -60,8 +71,9 @@ impl< + Clone, > Hash for T where - ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + ::Core: ProxyHash, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: generic_array::ArrayLength, { } diff --git a/src/key_exchange/group/curve25519.rs b/src/key_exchange/group/curve25519.rs index 509878b..7abc968 100644 --- a/src/key_exchange/group/curve25519.rs +++ b/src/key_exchange/group/curve25519.rs @@ -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(rng: &mut R) -> Self::Sk { + fn random_sk(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); diff --git a/src/key_exchange/group/ed25519.rs b/src/key_exchange/group/ed25519.rs index 6c7edeb..c84be14 100644 --- a/src/key_exchange/group/ed25519.rs +++ b/src/key_exchange/group/ed25519.rs @@ -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 { - let bytes = bytes.take_array("public key")?; + let bytes = bytes.take_array::("public key")?; VerifyingKey::from_bytes(bytes.into()) } - fn random_sk(rng: &mut R) -> Self::Sk { + fn random_sk(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 { Ok(SigningKey::from_bytes( - bytes.take_array("secret key")?.into(), + bytes.take_array::("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::deserialize_take(&mut bytes) @@ -407,9 +406,9 @@ impl Signature { fn deserialize_take(bytes: &mut &[u8]) -> Result { #[allow(non_snake_case)] - let R = CompressedEdwardsY(bytes.take_array("signature R")?.into()); + let R = CompressedEdwardsY(bytes.take_array::("signature R")?.into()); - let s = Scalar::from_canonical_bytes(bytes.take_array("signature s")?.into()) + let s = Scalar::from_canonical_bytes(bytes.take_array::("signature s")?.into()) .into_option() .ok_or(ProtocolError::SerializationError)?; @@ -417,7 +416,8 @@ impl Signature { } fn serialize(&self) -> GenericArray { - GenericArray::from(self.R.0).concat(GenericArray::from(self.s.to_bytes())) + GenericArray::::from(self.R.0) + .cat(GenericArray::::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(); diff --git a/src/key_exchange/group/elliptic_curve.rs b/src/key_exchange/group/elliptic_curve.rs index 85a9ae9..9092700 100644 --- a/src/key_exchange/group/elliptic_curve.rs +++ b/src/key_exchange/group/elliptic_curve.rs @@ -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 Group for G where Self: CurveArithmetic + voprf::CipherSuite + voprf::Group>, - FieldBytesSize: ModulusSize, + FieldBytesSize: ModulusSize + ArrayLength, + as ModulusSize>::CompressedPointSize: ArrayLength, ProjectivePoint: GroupEncoding< - Repr = GenericArray as ModulusSize>::CompressedPointSize>, - > + ToEncodedPoint, + Repr = hybrid_array::Array< + u8, + as ModulusSize>::CompressedPointSize, + >, + > + ToSec1Point, + // Bounds required by voprf::CipherSuite + ::SecurityLevel: Mul, + <::Hash as OutputSizeUser>::OutputSize: ArrayLength + + IsLess + + IsLessOrEqual< + <::Hash as BlockSizeUser>::BlockSize, + Output = True, + > + IsGreaterOrEqual::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; + type Pk = NonIdentity>; type PkLen = as ModulusSize>::CompressedPointSize; @@ -46,18 +59,19 @@ where type SkLen = FieldBytesSize; fn serialize_pk(pk: &Self::Pk) -> GenericArray { - 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 { - point::NonIdentity::>::from_bytes(&bytes.take_array("public key")?) - .into_option() - .map(NonIdentity) - .ok_or(ProtocolError::SerializationError) + NonIdentity::>::from_bytes( + &bytes.take_array("public key")?.into_ha0_4(), + ) + .into_option() + .ok_or(ProtocolError::SerializationError) } - fn random_sk(rng: &mut R) -> Self::Sk { - SecretKey::::random(rng) + fn random_sk(rng: &mut R) -> Self::Sk { + SecretKey::::generate_from_rng(rng) } fn derive_scalar(seed: GenericArray) -> Result { @@ -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::::mul_by_generator( - &sk.to_nonzero_scalar(), - )) - .expect("multiplying with a non-zero scalar can never yield the identity element"), - ) + NonIdentity::>::mul_by_generator(&sk.to_nonzero_scalar()) } fn serialize_sk(sk: &Self::Sk) -> GenericArray { - sk.to_bytes() + GenericArray::from(sk.to_bytes()) } fn deserialize_take_sk(bytes: &mut &[u8]) -> Result { - SecretKey::::from_bytes(&bytes.take_array("secret key")?) + SecretKey::::from_bytes(&bytes.take_array("secret key")?.into_ha0_4()) .map_err(|_| ProtocolError::SerializationError) } } @@ -92,51 +100,26 @@ where impl DiffieHellman for SecretKey where G: CurveArithmetic + voprf::CipherSuite + voprf::Group>, - FieldBytesSize: ModulusSize, + FieldBytesSize: ModulusSize + ArrayLength, + as ModulusSize>::CompressedPointSize: ArrayLength, ProjectivePoint: GroupEncoding< - Repr = GenericArray as ModulusSize>::CompressedPointSize>, - > + ToEncodedPoint, + Repr = hybrid_array::Array as ModulusSize>::CompressedPointSize>, + > + ToSec1Point, + ::SecurityLevel: Mul, + <::Hash as OutputSizeUser>::OutputSize: ArrayLength + + IsLess + + IsLessOrEqual<<::Hash as BlockSizeUser>::BlockSize, Output = True> + + IsGreaterOrEqual::SecurityLevel, U2>, Output = True>, { fn diffie_hellman( &self, - pk: &NonIdentity, + pk: &NonIdentity>, ) -> GenericArray 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>: serde::Deserialize<'de>", - serialize = "point::NonIdentity>: serde::Serialize" - ), - transparent - ) -)] -pub struct NonIdentity(pub point::NonIdentity>); - -impl Debug for NonIdentity { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_tuple("NonIdentity") - .field(&self.0.to_point()) - .finish() - } -} - -impl PartialEq for NonIdentity { - fn eq(&self, other: &Self) -> bool { - self.0.to_point().eq(&other.0.to_point()) - } -} - -impl Eq for NonIdentity {} diff --git a/src/key_exchange/group/mod.rs b/src/key_exchange/group/mod.rs index d3541fa..e1f89e9 100644 --- a/src/key_exchange/group/mod.rs +++ b/src/key_exchange/group/mod.rs @@ -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; + type PkLen: ArrayLength + ArraySize; /// Secret key type Sk: Clone + ZeroizeOnDrop; /// Length of the secret key - type SkLen: ArrayLength; + type SkLen: ArrayLength + ArraySize; /// Serializes `self` fn serialize_pk(pk: &Self::Pk) -> GenericArray; @@ -44,7 +45,7 @@ pub trait Group { fn deserialize_take_pk(bytes: &mut &[u8]) -> Result; /// Generate a random secret key - fn random_sk(rng: &mut R) -> Self::Sk; + fn random_sk(rng: &mut R) -> Self::Sk; /// Deterministically derive a [`Self::Sk`] from `seed`. fn derive_scalar(seed: GenericArray) -> Result; diff --git a/src/key_exchange/group/ristretto255.rs b/src/key_exchange/group/ristretto255.rs index 3acbce3..0c74721 100644 --- a/src/key_exchange/group/ristretto255.rs +++ b/src/key_exchange/group/ristretto255.rs @@ -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 { - CompressedRistretto(bytes.take_array("public key")?.into()) + CompressedRistretto(bytes.take_array::("public key")?.into()) .decompress() .ok_or(ProtocolError::SerializationError) .and_then(NonIdentity::from_point) } - fn random_sk(rng: &mut R) -> Self::Sk { + fn random_sk(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 { - Scalar::from_canonical_bytes(bytes.take_array("secret key")?.into()) + Scalar::from_canonical_bytes(bytes.take_array::("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 = ::Group; @@ -165,13 +170,17 @@ impl voprf::Group for Ristretto255 { type ScalarLen = ::ScalarLen; + type SecurityLevel = ::SecurityLevel; + fn hash_to_curve( input: &[&[u8]], dst: &[&[u8]], ) -> voprf::Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, - H::OutputSize: IsLess + IsLessOrEqual, + H::OutputSize: IsLess + + IsLessOrEqual + + IsGreaterOrEqual::SecurityLevel, U2>, Output = True>, { ::hash_to_curve::(input, dst) } @@ -182,7 +191,9 @@ impl voprf::Group for Ristretto255 { ) -> voprf::Result where H: BlockSizeUser + Default + FixedOutput + HashMarker, - H::OutputSize: IsLess + IsLessOrEqual, + H::OutputSize: IsLess + + IsLessOrEqual + + IsGreaterOrEqual::SecurityLevel, U2>, Output = True>, { ::hash_to_scalar::(input, dst) } @@ -195,7 +206,7 @@ impl voprf::Group for Ristretto255 { ::identity_elem() } - fn serialize_elem(elem: Self::Elem) -> GenericArray { + fn serialize_elem(elem: Self::Elem) -> Array { ::serialize_elem(elem) } @@ -203,7 +214,7 @@ impl voprf::Group for Ristretto255 { ::deserialize_elem(element_bits) } - fn random_scalar(rng: &mut R) -> Self::Scalar { + fn random_scalar(rng: &mut R) -> voprf::Result { ::random_scalar(rng) } @@ -215,7 +226,7 @@ impl voprf::Group for Ristretto255 { ::is_zero_scalar(scalar) } - fn serialize_scalar(scalar: Self::Scalar) -> GenericArray { + fn serialize_scalar(scalar: Self::Scalar) -> Array { ::serialize_scalar(scalar) } diff --git a/src/key_exchange/mod.rs b/src/key_exchange/mod.rs index 2facee9..0f0ef5d 100644 --- a/src/key_exchange/mod.rs +++ b/src/key_exchange/mod.rs @@ -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 ::Core: ProxyHash, - <::Core as BlockSizeUser>::BlockSize: IsLess, - Le<<::Core as BlockSizeUser>::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: 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( + fn generate_ke1( rng: &mut R, ) -> Result, ProtocolError>; /// Server generates [`KE2Builder`](Self::KE2Builder). - fn ke2_builder<'a, CS: CipherSuite, R: RngCore + CryptoRng>( + fn ke2_builder<'a, CS: CipherSuite, R: Rng + CryptoRng>( rng: &mut R, credential_request: SerializedCredentialRequest, 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, R: CryptoRng + RngCore>( + fn generate_ke2_input, R: CryptoRng + Rng>( builder: &Self::KE2Builder<'_, CS>, rng: &mut R, server_s_sk: &PrivateKey, @@ -107,7 +109,7 @@ where /// Client generates [`KE3Message`](Self::KE3Message) and the session key. #[allow(clippy::too_many_arguments)] - fn generate_ke3, R: CryptoRng + RngCore>( + fn generate_ke3, R: CryptoRng + Rng>( rng: &mut R, credential_request: SerializedCredentialRequest, ke1_message: Self::KE1Message, @@ -137,7 +139,7 @@ where )] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize)] pub struct SerializedCredentialRequest( - GenericArray as voprf::Group>::ElemLen>, + Array as voprf::Group>::ElemLen>, ); impl SerializedCredentialRequest { @@ -154,17 +156,20 @@ impl SerializedCredentialRequest { /// Returns a [`SerializedCredentialRequest`] deserialized from the given /// `bytes`. pub fn deserialize_take(bytes: &mut &[u8]) -> Result { - Ok(Self(bytes.take_array("blinded element")?)) + Ok(Self(bytes.take_array("blinded element")?.into_ha0_4())) } } type SerializedCredentialRequestLen = as voprf::Group>::ElemLen; -impl Serialize for SerializedCredentialRequest { +impl Serialize for SerializedCredentialRequest +where + as voprf::Group>::ElemLen: ArrayLength, +{ type Len = SerializedCredentialRequestLen; fn serialize(&self) -> GenericArray { - self.0.clone() + GenericArray::from_slice(self.0.as_slice()).clone() } } @@ -176,7 +181,7 @@ impl Serialize for SerializedCredentialRequest { )] #[derive_where(Clone, Debug, Eq, Hash, PartialEq, Zeroize)] pub struct SerializedCredentialResponse { - evaluation_element: GenericArray as voprf::Group>::ElemLen>, + evaluation_element: Array as voprf::Group>::ElemLen>, masking_nonce: GenericArray, masked_response: MaskedResponse, } @@ -207,7 +212,7 @@ impl SerializedCredentialResponse { /// `bytes`. pub fn deserialize_take(input: &mut &[u8]) -> Result { 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 Serialize for SerializedCredentialResponse where as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - SerializedCredentialResponseLen: ArrayLength, + ArrayLength + Add>, + SerializedCredentialResponseLen: ArrayLength, { type Len = SerializedCredentialResponseLen; fn serialize(&self) -> GenericArray { - self.evaluation_element - .clone() - .concat(self.masking_nonce) - .concat(self.masked_response.serialize()) + let elem = GenericArray:: 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; + type Len: ArrayLength; /// Serialize [`Self`] to a fixed-length byte array. fn serialize(&self) -> GenericArray; diff --git a/src/key_exchange/shared.rs b/src/key_exchange/shared.rs index 0541d9c..66d8616 100644 --- a/src/key_exchange/shared.rs +++ b/src/key_exchange/shared.rs @@ -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 { pub(super) struct Ke2BuilderCommon where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, G::Sk: DiffieHellman, { pub(super) server_nonce: GenericArray, @@ -126,7 +128,7 @@ where // Helper functions pub(super) fn generate_ke1< - R: RngCore + CryptoRng, + R: Rng + CryptoRng, KE: KeyExchange, KE1Message = Ke1Message>, 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(rng: &mut R) -> GenericArray { +pub(super) fn generate_nonce(rng: &mut R) -> GenericArray { 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, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, G::Sk: DiffieHellman, CS::KeyExchange: KeyExchange, { @@ -238,8 +241,9 @@ pub(super) fn derive_keys<'a, H: Hash>( ) -> Result, ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { let mut hkdf = HkdfExtract::::new(None); @@ -280,19 +284,20 @@ pub(super) fn compute_ke2_macs( ) -> Result<(Output, Output), ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { let mut mac_hasher = - Hmac::::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; + SimpleHmac::::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::::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; + SimpleHmac::::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, Output), ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { let transcript_digest = transcript_hasher.clone().finalize(); let derived_keys = derive_keys::(shared_secrets, &transcript_digest)?; let mut server_mac_hasher = - Hmac::::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; + SimpleHmac::::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::::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; + SimpleHmac::::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( ) -> Result, ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { let h = Hkdf::::from_prk(secret).map_err(|_| InternalError::HkdfError)?; hkdf_expand_label_extracted(&h, label, context) @@ -356,10 +363,11 @@ fn hkdf_expand_label_extracted( ) -> Result, ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { - let mut okm = GenericArray::default(); + let mut okm = GenericArray::default().into_ha0_4(); let length = i2osp::(OutputSize::::USIZE)?; let label_length = i2osp::(STR_OPAQUE.len() + label.len())?; @@ -386,8 +394,9 @@ fn derive_secrets( ) -> Result, ProtocolError> where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { hkdf_expand_label_extracted::(hkdf, label, hashed_derivation_transcript) } @@ -407,12 +416,14 @@ impl Serialize for Ke1State where // Ke1State: KeSk + Nonce G::SkLen: Add, - Sum: ArrayLength, + Sum: ArrayLength, { type Len = Sum; fn serialize(&self) -> GenericArray { - 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 Serialize for Ke1Message where // Ke1Message: Nonce + KePk NonceLen: Add, - Sum: ArrayLength, + Sum: ArrayLength, { type Len = Sum; @@ -476,7 +487,7 @@ impl Ke1MessageIter { impl Ke1MessageIter where NonceLen: Add, - Ke1MessageIterLen: ArrayLength, + Ke1MessageIterLen: ArrayLength, { pub(crate) fn serialize(&self) -> GenericArray> { self.client_nonce.concat(self.client_e_pk.clone()) diff --git a/src/key_exchange/sigma_i/ecdsa.rs b/src/key_exchange/sigma_i/ecdsa.rs index aedaddc..0ebd884 100644 --- a/src/key_exchange/sigma_i/ecdsa.rs +++ b/src/key_exchange/sigma_i/ecdsa.rs @@ -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(PhantomData<(G, H)>); impl SignatureProtocol for Ecdsa where - G: CurveArithmetic + Group, Pk = NonIdentity> + PrimeCurve, - SignatureSize: ArrayLength, - H: Clone - + Default - + BlockSizeUser - + FixedOutputReset> - + HashMarker, + G: CurveArithmetic + + Group, Pk = NonIdentity>> + + EcdsaCurve, + SignatureSize: ArrayLength + ArraySize, + H: EagerHash + FixedOutputReset + BlockSizeUser + HashMarker + Digest + Clone + Default, { type Group = G; - type Signature = Signature; + type Signature = ecdsa::Signature; type SignatureLen = SignatureSize; type VerifyState = PreHash; // 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: &::Sk, rng: &mut R, message: &Message, @@ -63,7 +57,7 @@ where let hash = message.hash::(); ( - 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, signature: &Self::Signature, ) -> Result<(), ProtocolError> { - verify(pk, &state.0, &signature.0) + verify(pk, &state.0, signature) } fn serialize_signature(signature: &Self::Signature) -> GenericArray { - signature.0.to_bytes() + GenericArray::from_slice(signature.to_bytes().as_slice()).clone() } fn deserialize_take_signature(bytes: &mut &[u8]) -> Result { - 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(sk: &SecretKey, rng: &mut R, pre_hash: &[u8]) -> ecdsa::Signature where - R: CryptoRng + RngCore, - C: CurveArithmetic + PrimeCurve, - SignatureSize: ArrayLength, - H: Default + BlockSizeUser + FixedOutputReset> + HashMarker, + R: CryptoRng + Rng, + C: CurveArithmetic + EcdsaCurve, + SignatureSize: ArraySize, + H: Digest + BlockSizeUser + FixedOutputReset, { - let repr = sk.to_bytes(); - let order = C::ORDER.encode_field_bytes(); - let z = - hazmat::bits2field::(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::::default(); - rng.fill_bytes(&mut ad); - - let k = - Scalar::::from_repr(rfc6979::generate_k::(&repr, &order, &z, &ad)).unwrap(); - - if let Ok((signature, _)) = hazmat::sign_prehashed::(&sk.to_nonzero_scalar(), k, &z) { - break signature; - } - } + let mut ad = FieldBytes::::default(); + rng.fill_bytes(&mut ad); + ecdsa::hazmat::sign_prehashed_rfc6979::(&sk.to_nonzero_scalar(), pre_hash, &ad).0 } fn verify( - pk: &NonIdentity, + pk: &NonIdentity>, pre_hash: &[u8], signature: &ecdsa::Signature, ) -> Result<(), ProtocolError> where - C: CurveArithmetic + PrimeCurve, - SignatureSize: ArrayLength, + C: CurveArithmetic + EcdsaCurve, + SignatureSize: ArraySize, { - let z = - hazmat::bits2field::(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(pub ecdsa::Signature) -where - SignatureSize: ArrayLength; - -impl Zeroize for Signature -where - SignatureSize: ArrayLength, -{ - fn zeroize(&mut self) { - self.0 = ecdsa::Signature::from_scalars( - Into::>::into(Scalar::::ONE), - Into::>::into(Scalar::::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(); } diff --git a/src/key_exchange/sigma_i/hash_eddsa.rs b/src/key_exchange/sigma_i/hash_eddsa.rs index 02a45bf..a1454a1 100644 --- a/src/key_exchange/sigma_i/hash_eddsa.rs +++ b/src/key_exchange/sigma_i/hash_eddsa.rs @@ -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 SignatureProtocol for HashEddsa { type SignatureLen = G::SignatureLen; type VerifyState = G::VerifyState; - fn sign<'a, R: CryptoRng + RngCore, CS: CipherSuite, KE: Group>( + fn sign<'a, R: CryptoRng + Rng, CS: CipherSuite, KE: Group>( sk: &::Sk, _: &mut R, message: &Message, @@ -66,7 +66,7 @@ pub(in super::super) mod implementation { pub trait HashEddsaImpl: Group { type Signature: Clone + Zeroize; - type SignatureLen: ArrayLength; + type SignatureLen: ArrayLength; type VerifyState: Clone + Zeroize; fn sign( diff --git a/src/key_exchange/sigma_i/message.rs b/src/key_exchange/sigma_i/message.rs index 01c0ac7..927b165 100644 --- a/src/key_exchange/sigma_i/message.rs +++ b/src/key_exchange/sigma_i/message.rs @@ -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 Deserialize for CachedMessage { 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 = Sum< impl Serialize for CachedMessage where - SerializedCredentialRequestLen: ArrayLength + Add>, + SerializedCredentialRequestLen: ArrayLength + Add>, Sum, Ke1MessageIterLen>: - ArrayLength + Add>, + ArrayLength + Add>, Sum< Sum, Ke1MessageIterLen>, SerializedCredentialResponseLen, - >: ArrayLength + Add, + >: ArrayLength + Add, Sum< Sum< Sum, Ke1MessageIterLen>, SerializedCredentialResponseLen, >, NonceLen, - >: ArrayLength + Add, + >: ArrayLength + Add, Sum< Sum< Sum< @@ -287,26 +286,26 @@ where NonceLen, >, KE::PkLen, - >: ArrayLength + Add>>, - CachedMessageLen: ArrayLength, + >: ArrayLength + Add>>, + CachedMessageLen: ArrayLength, // Ke1MessageIter NonceLen: Add, - Ke1MessageIterLen: ArrayLength, + Ke1MessageIterLen: ArrayLength, // CredentialResponseParts as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - SerializedCredentialResponseLen: ArrayLength, + ArrayLength + Add>, + SerializedCredentialResponseLen: ArrayLength, { type Len = CachedMessageLen; fn serialize(&self) -> GenericArray { 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()) } } diff --git a/src/key_exchange/sigma_i/mod.rs b/src/key_exchange/sigma_i/mod.rs index d0cfcc1..f11982c 100644 --- a/src/key_exchange/sigma_i/mod.rs +++ b/src/key_exchange/sigma_i/mod.rs @@ -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; + 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( + fn sign( sk: &::Sk, rng: &mut R, message: &Message, @@ -202,8 +202,9 @@ pub struct Ke2State { pub struct Ke2Message where KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { server_nonce: GenericArray, #[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 { +pub struct Ke3Message +where + ::OutputSize: ArrayLength, +{ signature: SIG::Signature, mac: Output, } -impl KeyExchange for SigmaI +impl KeyExchange + for SigmaI where KE::Sk: DiffieHellman, KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { type Group = SIG::Group; type Hash = KEH; type KE1State = Ke1State; + type KE2State = Ke2State; type KE1Message = Ke1Message; type KE2Builder<'a, CS: CipherSuite> = Ke2Builder<'a, CS, KE>; type KE2BuilderData<'a, CS: 'static + CipherSuite> = &'a Message<'a, CS, KE>; type KE2BuilderInput = (SIG::Signature, SIG::VerifyState); - type KE2State = Ke2State; type KE2Message = Ke2Message; type KE3Message = Ke3Message; - fn generate_ke1( + fn generate_ke1( rng: &mut R, ) -> Result, ProtocolError> { generate_ke1(rng) } - fn ke2_builder<'a, CS: CipherSuite, R: RngCore + CryptoRng>( + fn ke2_builder<'a, CS: CipherSuite, R: Rng + CryptoRng>( rng: &mut R, credential_request: SerializedCredentialRequest, ke1_message: Self::KE1Message, @@ -287,13 +293,13 @@ where &transcript_hasher.finalize(), )?; - let mut server_mac = - Hmac::::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; + let mut server_mac = SimpleHmac::::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::::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; + let mut client_mac = SimpleHmac::::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, R: CryptoRng + RngCore>( + fn generate_ke2_input, R: CryptoRng + Rng>( builder: &Self::KE2Builder<'_, CS>, rng: &mut R, server_s_sk: &PrivateKey, @@ -363,7 +369,7 @@ where }) } - fn generate_ke3, R: CryptoRng + RngCore>( + fn generate_ke3, R: CryptoRng + Rng>( rng: &mut R, credential_request: SerializedCredentialRequest, ke1_message: Self::KE1Message, @@ -397,8 +403,8 @@ where &transcript_hasher.finalize(), )?; - let mut server_mac = - Hmac::::new_from_slice(&derived_keys.km2).map_err(|_| InternalError::HmacError)?; + let mut server_mac = SimpleHmac::::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::::new_from_slice(&derived_keys.km3).map_err(|_| InternalError::HmacError)?; + let mut client_mac = SimpleHmac::::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 Deserialize for Ke2State where SIG::VerifyState: Deserialize, + OutputSize>: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { 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::::deserialize_take(input)?, + expected_mac: input.take_array("expected mac")?.into_ha0_4(), }) } } @@ -502,37 +509,44 @@ type VerifyStateLen = impl Serialize for Ke2State where SIG::VerifyState: Serialize, + OutputSize>: ArrayLength, // Ke2State: ((SigPk + Hash) + VerifyState) + Hash ::PkLen: Add>>, Sum<::PkLen, OutputSize>>: - ArrayLength + Add>, + ArrayLength + Add>, Sum::PkLen, OutputSize>>, VerifyStateLen>: - ArrayLength + Add>>, - Ke2StateLen: ArrayLength, + ArrayLength + Add>>, + Ke2StateLen: ArrayLength, { type Len = Ke2StateLen; fn serialize(&self) -> GenericArray { - 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 Deserialize for Ke2Message where KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { 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 Serialize for Ke2Message where KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, // Ke2Message: ((Nonce + KePk) + Signature) + Hash NonceLen: Add, - Sum: ArrayLength + Add, - Sum, SIG::SignatureLen>: ArrayLength + Add>, - Sum, SIG::SignatureLen>, OutputSize>: ArrayLength, + Sum: ArrayLength + Add, + Sum, SIG::SignatureLen>: ArrayLength + Add>, + Sum, SIG::SignatureLen>, OutputSize>: ArrayLength, { type Len = Sum, SIG::SignatureLen>, OutputSize>; fn serialize(&self) -> GenericArray { 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 Deserialize for Ke3Message where KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { 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 Serialize for Ke3Message where KEH::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, // Ke2Message: Signature + Hash SIG::SignatureLen: Add>, - Sum>: ArrayLength, + Sum>: ArrayLength, { type Len = Sum>; fn serialize(&self) -> GenericArray { - SIG::serialize_signature(&self.signature).concat(self.mac.clone()) + Concat::concat( + SIG::serialize_signature(&self.signature), + GenericArray::from_slice(self.mac.as_slice()).clone(), + ) } } diff --git a/src/key_exchange/sigma_i/pure_eddsa.rs b/src/key_exchange/sigma_i/pure_eddsa.rs index 5691959..d5e76cc 100644 --- a/src/key_exchange/sigma_i/pure_eddsa.rs +++ b/src/key_exchange/sigma_i/pure_eddsa.rs @@ -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 SignatureProtocol for PureEddsa { type SignatureLen = G::SignatureLen; type VerifyState = CachedMessage; - 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, @@ -51,13 +51,13 @@ impl SignatureProtocol for PureEddsa { G::verify(pk, message_builder, state, signature) } - fn deserialize_take_signature(bytes: &mut &[u8]) -> Result { - G::deserialize_take_signature(bytes) - } - fn serialize_signature(signature: &Self::Signature) -> GenericArray { G::serialize_signature(signature) } + + fn deserialize_take_signature(bytes: &mut &[u8]) -> Result { + 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; + type SignatureLen: ArrayLength; fn sign( sk: &Self::Sk, diff --git a/src/key_exchange/sigma_i/shared.rs b/src/key_exchange/sigma_i/shared.rs index 27346d3..5aef114 100644 --- a/src/key_exchange/sigma_i/shared.rs +++ b/src/key_exchange/sigma_i/shared.rs @@ -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; >::ArrayType)] #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound = "") )] +#[allow(dead_code)] pub struct PreHash(pub Output); -impl Deserialize for PreHash { +impl Deserialize for PreHash +where + H::OutputSize: ArrayLength, +{ fn deserialize_take(input: &mut &[u8]) -> Result { - Ok(Self(input.take_array("pre-hash")?)) + Ok(Self(input.take_array("pre-hash")?.into_ha0_4())) } } -impl Serialize for PreHash { +impl Serialize for PreHash +where + H::OutputSize: ArrayLength, +{ type Len = H::OutputSize; fn serialize(&self) -> GenericArray { - self.0.clone() + GenericArray::from_slice(self.0.as_slice()).clone() } } diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 2d1f8b5..0c37147 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -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 { pub struct Ke2Builder where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { server_nonce: GenericArray, transcript_hasher: H, @@ -104,8 +104,9 @@ where pub struct Ke2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { pub(super) server_nonce: GenericArray, #[derive_where(skip(Zeroize))] @@ -123,8 +124,9 @@ where pub struct Ke3Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { pub(super) mac: Output, } @@ -138,8 +140,9 @@ impl KeyExchange for TripleDh where G::Sk: DiffieHellman, H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { type Group = G; type Hash = H; @@ -153,13 +156,13 @@ where type KE2Message = Ke2Message; type KE3Message = Ke3Message; - fn generate_ke1( + fn generate_ke1( rng: &mut R, ) -> Result, ProtocolError> { shared::generate_ke1(rng) } - fn ke2_builder<'a, CS: CipherSuite, R: RngCore + CryptoRng>( + fn ke2_builder<'a, CS: CipherSuite, R: Rng + CryptoRng>( rng: &mut R, credential_request: SerializedCredentialRequest, ke1_message: Self::KE1Message, @@ -201,7 +204,7 @@ where &builder.client_e_pk } - fn generate_ke2_input, R: CryptoRng + RngCore>( + fn generate_ke2_input, R: CryptoRng + Rng>( builder: &Self::KE2Builder<'_, CS>, _: &mut R, server_s_sk: &PrivateKey, @@ -247,7 +250,7 @@ where }) } - fn generate_ke3, R: CryptoRng + RngCore>( + fn generate_ke3, R: CryptoRng + Rng>( _: &mut R, credential_request: SerializedCredentialRequest, ke1_message: Self::KE1Message, @@ -319,13 +322,14 @@ where impl Deserialize for Ke2State where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { 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 Serialize for Ke2State where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, // Ke2State: Hash + Hash OutputSize: Add>, - Sum, OutputSize>: ArrayLength, + Sum, OutputSize>: ArrayLength, { type Len = Sum, OutputSize>; fn serialize(&self) -> GenericArray { - self.session_key.clone().concat(self.expected_mac.clone()) + let sk: GenericArray> = + GenericArray::from_slice(self.session_key.as_slice()).clone(); + let mac: GenericArray> = + 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 Drop for Ke2Builder where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: 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 ZeroizeOnDrop for Ke2Builder where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { } impl Deserialize for Ke2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { 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 Serialize for Ke2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, // Ke2Message: (Nonce + KePk) + Hash NonceLen: Add, - Sum: ArrayLength + Add>, - Sum, OutputSize>: ArrayLength, + Sum: ArrayLength + Add>, + Sum, OutputSize>: ArrayLength, { type Len = Sum, OutputSize>; fn serialize(&self) -> GenericArray { 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 Deserialize for Ke3Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { fn deserialize_take(bytes: &mut &[u8]) -> Result { Ok(Self { - mac: bytes.take_array("mac")?, + mac: bytes.take_array("mac")?.into_ha0_4(), }) } } @@ -429,12 +443,13 @@ where impl Serialize for Ke3Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + OutputSize: ArrayLength, { type Len = OutputSize; fn serialize(&self) -> GenericArray { - self.mac.clone() + GenericArray::from_slice(self.mac.as_slice()).clone() } } diff --git a/src/key_exchange/tripledh_kem.rs b/src/key_exchange/tripledh_kem.rs index 099cbeb..e843a2b 100644 --- a/src/key_exchange/tripledh_kem.rs +++ b/src/key_exchange/tripledh_kem.rs @@ -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; + type EncapsulationKeyLen: ArrayLength + ArraySize; /// Length (in bytes) of the serialized secret key. - type DecapsulationKeyLen: ArrayLength; + type DecapsulationKeyLen: ArrayLength + ArraySize; /// Length (in bytes) of the encapsulated ciphertext. - type CiphertextLen: ArrayLength; + type CiphertextLen: ArrayLength + ArraySize; /// Length (in bytes) of the shared secret output by the KEM. - type SharedSecretLen: ArrayLength; + type SharedSecretLen: ArrayLength + ArraySize; /// Generates a fresh KEM key pair. - fn generate( + fn generate( 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( + fn encapsulate( 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 rand_core_10::TryRng for RngCompat<'_, R> { +impl rand_core::TryRng for RngCompat<'_, R> { type Error = core::convert::Infallible; fn try_next_u32(&mut self) -> Result { @@ -137,7 +137,7 @@ impl rand_core_10::TryRng for RngCompat<'_, R> { } } -impl rand_core_10::TryCryptoRng for RngCompat<'_, R> {} +impl rand_core::TryCryptoRng for RngCompat<'_, R> {} type RcEncapsulationKeyLen = <::EncapsulationKey as KeySizeUser>::KeySize; #[allow(deprecated)] @@ -152,10 +152,10 @@ where K: MlKemTrait, K::EncapsulationKey: Encapsulate + KeyExport + TryKeyInit + Clone, K::DecapsulationKey: Decapsulate + ExpandedKeyEncoding + Clone + ZeroizeOnDrop, - RcEncapsulationKeyLen: ArrayLength, - RcDecapsulationKeyLen: ArrayLength, - RcCiphertextLen: ArrayLength, - RcSharedSecretLen: ArrayLength, + RcEncapsulationKeyLen: ArrayLength + ArraySize, + RcDecapsulationKeyLen: ArrayLength + ArraySize, + RcCiphertextLen: ArrayLength + ArraySize, + RcSharedSecretLen: ArrayLength + ArraySize, { type EncapsulationKey = K::EncapsulationKey; type DecapsulationKey = K::DecapsulationKey; @@ -164,7 +164,7 @@ where type CiphertextLen = RcCiphertextLen; type SharedSecretLen = RcSharedSecretLen; - fn generate( + fn generate( 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 { - 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 { - 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( + fn encapsulate( 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::::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 { pub struct KemKe2State where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, { base_state: super::tripledh::Ke2State, kem_encapsulation_key: GenericArray, @@ -295,8 +297,10 @@ where pub struct KemKe2Builder where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, { server_nonce: GenericArray, transcript_hasher: H, @@ -323,8 +327,10 @@ where pub struct KemKe2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, { dh_message: super::tripledh::Ke2Message, kem_ciphertext: GenericArray, @@ -338,13 +344,15 @@ where G: Group, H: Hash, H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: 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, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, K: KemCoreWrapper, { } @@ -369,11 +379,13 @@ where G::Sk: shared::DiffieHellman, H: Hash, H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, K: KemCoreWrapper, NonceLen: Add, - Sum: ArrayLength, + Sum: ArrayLength, { type Group = G; type Hash = H; @@ -390,7 +402,7 @@ where type KE2Message = KemKe2Message; type KE3Message = KemKe3Message; - fn generate_ke1( + fn generate_ke1( rng: &mut R, ) -> Result, ProtocolError> { let base = super::tripledh::TripleDh::::generate_ke1(rng)?; @@ -409,7 +421,7 @@ where }) } - fn ke2_builder<'a, CS: CipherSuite, R: RngCore + CryptoRng>( + fn ke2_builder<'a, CS: CipherSuite, R: Rng + CryptoRng>( rng: &mut R, credential_request: SerializedCredentialRequest, 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, R: CryptoRng + RngCore>( + fn generate_ke2_input, R: CryptoRng + Rng>( builder: &Self::KE2Builder<'_, CS>, _: &mut R, server_s_sk: &PrivateKey, @@ -516,7 +531,7 @@ where }) } - fn generate_ke3, R: CryptoRng + RngCore>( + fn generate_ke3, R: CryptoRng + Rng>( _rng: &mut R, credential_request: SerializedCredentialRequest, 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 Serialize for KemKe1State where Ke1State: Serialize, as Serialize>::Len: Add, - Sum< as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength, + Sum< as Serialize>::Len, K::DecapsulationKeyLen>: ArrayLength, { type Len = Sum< as Serialize>::Len, K::DecapsulationKeyLen>; fn serialize(&self) -> GenericArray { 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 Serialize for KemKe1Message where Ke1Message: Serialize, as Serialize>::Len: Add, - Sum< as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength, + Sum< as Serialize>::Len, K::EncapsulationKeyLen>: ArrayLength, { type Len = Sum< as Serialize>::Len, K::EncapsulationKeyLen>; fn serialize(&self) -> GenericArray { self.dh_message .serialize() - .concat(self.kem_encapsulation_key.clone()) + .cat(self.kem_encapsulation_key.clone()) } } impl Deserialize for KemKe2State where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { Ok(Self { @@ -659,16 +682,18 @@ where impl Serialize for KemKe2State where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, super::tripledh::Ke2State: Serialize, as Serialize>::Len: Add, Sum< as Serialize>::Len, K::EncapsulationKeyLen>: - ArrayLength + Add, + ArrayLength + Add, Sum< Sum< as Serialize>::Len, K::EncapsulationKeyLen>, K::CiphertextLen, - >: ArrayLength, + >: ArrayLength, { type Len = Sum< Sum< as Serialize>::Len, K::EncapsulationKeyLen>, @@ -678,16 +703,18 @@ where fn serialize(&self) -> GenericArray { 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 Deserialize for KemKe2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, { fn deserialize_take(input: &mut &[u8]) -> Result { Ok(Self { @@ -700,21 +727,21 @@ where impl Serialize for KemKe2Message where H::Core: ProxyHash, - ::BlockSize: IsLess, - Le<::BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: IsLess, + Le<<::Core as SmallBlockSizeUser>::_BlockSize, U256>: NonZero, + <::Core as SmallBlockSizeUser>::_BlockSize: Cmp, + OutputSize: ArrayLength, NonceLen: Add, - Sum: ArrayLength + Add>, - Sum, OutputSize>: ArrayLength, + Sum: ArrayLength + Add>, + Sum, OutputSize>: ArrayLength, super::tripledh::Ke2Message: Serialize, as Serialize>::Len: Add, < as Serialize>::Len as Add>::Output: - ArrayLength, + ArrayLength, { type Len = Sum< as Serialize>::Len, K::CiphertextLen>; fn serialize(&self) -> GenericArray { - self.dh_message - .serialize() - .concat(self.kem_ciphertext.clone()) + self.dh_message.serialize().cat(self.kem_ciphertext.clone()) } } diff --git a/src/keypair.rs b/src/keypair.rs index f653cc7..721abaa 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -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> { pk: PublicKey, sk: SK, @@ -60,7 +56,7 @@ impl KeyPair { } impl KeyPair { - pub(crate) fn random(rng: &mut R) -> Self { + pub(crate) fn random(rng: &mut R) -> Self { let sk = G::random_sk(rng); let pk = G::public_key(&sk); Self { @@ -70,7 +66,7 @@ impl KeyPair { } /// Generating a random key pair given a cryptographic rng - pub(crate) fn derive_random(rng: &mut R) -> Self { + pub(crate) fn derive_random(rng: &mut R) -> Self { let mut scalar_bytes = GenericArray::<_, ::SkLen>::default(); rng.fill_bytes(&mut scalar_bytes); let sk = G::derive_scalar(scalar_bytes).unwrap(); @@ -133,7 +129,7 @@ where impl PrivateKey { /// Private-key signing implementation pub(crate) fn sign< - R: CryptoRng + RngCore, + R: CryptoRng + Rng, CS: CipherSuite, SIG: SignatureProtocol, KE: Group, @@ -152,7 +148,7 @@ pub trait PrivateKeySerialization: Clone { /// Custom error type that can be passed down to `ProtocolError::Custom` type Error; /// Serialization size in bytes. - type Len: ArrayLength; + type Len: ArrayLength; /// Serialization into bytes fn serialize_key_pair(key_pair: &KeyPair) -> GenericArray; @@ -242,7 +238,7 @@ pub struct OprfSeed(pub(crate) Output); /// Will be called with `E` being [`PrivateKeySerialization::Error`]. pub trait OprfSeedSerialization: Sized { /// Serialization size in bytes. - type Len: ArrayLength; + type Len: ArrayLength; /// Serialization into bytes fn serialize(&self) -> GenericArray; @@ -253,18 +249,22 @@ pub trait OprfSeedSerialization: Sized { fn deserialize_take(bytes: &mut &[u8]) -> Result>; } -impl OprfSeedSerialization for OprfSeed { +impl OprfSeedSerialization for OprfSeed +where + H::OutputSize: ArrayLength, +{ type Len = H::OutputSize; fn serialize(&self) -> GenericArray { - self.0.clone() + GenericArray::from_slice(self.0.as_slice()).clone() } fn deserialize_take(input: &mut &[u8]) -> Result> { 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 OprfSeedSerialization for OprfSeed { ////////////////////////// #[cfg(test)] -impl KeyPair { +impl KeyPair +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 { @@ -297,9 +301,6 @@ impl KeyPair { #[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::::random_sk(&mut OsRng)); + let sk = PrivateKey(KeGroup::::random_sk(&mut UnwrapErr(SysRng))); let pk = sk.public_key(); let sk = RemoteKey(sk); let keypair = KeyPair::new(sk, pk); let server_setup = - ServerSetup::::new_with_key_pair(&mut OsRng, keypair); + ServerSetup::::new_with_key_pair(&mut UnwrapErr(SysRng), keypair); let ClientRegistrationStartResult { message, state: client, - } = ClientRegistration::::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); + } = ClientRegistration::::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::::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); + } = ClientLogin::::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::>(GenericArray::default()); - OsRng.fill_bytes(&mut oprf_seed.0); + let mut oprf_seed = RemoteSeed::>(GenericArray::default().into_ha0_4()); + UnwrapErr(SysRng).fill_bytes(&mut oprf_seed.0); - let sk = PrivateKey(KeGroup::::random_sk(&mut OsRng)); + let sk = PrivateKey(KeGroup::::random_sk(&mut UnwrapErr(SysRng))); let pk = sk.public_key(); let sk = RemoteKey(sk); let keypair = KeyPair::new(sk, pk); let server_setup = ServerSetup::::new_with_key_pair_and_seed( - &mut OsRng, keypair, oprf_seed, + &mut UnwrapErr(SysRng), + keypair, + oprf_seed, ); let ClientRegistrationStartResult { message, state: client, - } = ClientRegistration::::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); + } = ClientRegistration::::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()) + .unwrap(); let km = server_setup.key_material_info(&[]); let mut ikm = GenericArray::default(); Hkdf::>::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::::start(&mut OsRng, PASSWORD.as_bytes()).unwrap(); + } = ClientLogin::::start(&mut UnwrapErr(SysRng), PASSWORD.as_bytes()).unwrap(); let km = server_setup.key_material_info(&[]); let mut ikm = GenericArray::default(); Hkdf::>::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(), diff --git a/src/ksf.rs b/src/ksf.rs index b14e430..61a0e3c 100644 --- a/src/ksf.rs +++ b/src/ksf.rs @@ -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>( + fn hash( &self, input: GenericArray, ) -> Result, InternalError>; @@ -26,7 +26,7 @@ pub trait Ksf: Default { pub struct Identity; impl Ksf for Identity { - fn hash>( + fn hash( &self, input: GenericArray, ) -> Result, InternalError> { @@ -36,7 +36,7 @@ impl Ksf for Identity { #[cfg(feature = "argon2")] impl Ksf for argon2::Argon2<'_> { - fn hash>( + fn hash( &self, input: GenericArray, ) -> Result, InternalError> { diff --git a/src/lib.rs b/src/lib.rs index f9cd29c..860d6d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; -//! type Ksf = opaque_ke::ksf::Identity; +//! type OprfCs = opaque_vx::Ristretto255; +//! type KeyExchange = opaque_vx::TripleDh; +//! 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::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::::new(&mut server_rng); //! let server_registration_start_result = ServerRegistration::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; -//! 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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"alice@example.com", 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! // 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! // 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; -//! type Ksf = opaque_ke::ksf::Identity; +//! type OprfCs = opaque_vx::Ristretto255; +//! type KeyExchange = opaque_vx::TripleDhKem; +//! 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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::::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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # 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::::start( //! # &mut client_rng, //! # b"password", //! # )?; -//! # let mut server_rng = OsRng; +//! # let mut server_rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut server_rng); //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; //! # 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 = <::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 = <::KeyExchange as KeyExchange>::Group; //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfCs = opaque_ke::Ristretto255; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[derive(Debug, thiserror::Error)] //! # #[error("test error")] @@ -1034,9 +1051,9 @@ //! # Ok(<::Sk as DiffieHellman>::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 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::::new_with_key_pair(&mut server_rng, keypair); //! //! # let client_registration_start_result = ClientRegistration::::start( -//! # &mut OsRng, +//! # &mut UnwrapErr(SysRng), //! # b"password", //! # )?; //! # let server_registration_start_result = ServerRegistration::::start(&server_setup, client_registration_start_result.message, b"alice@example.com")?; -//! # 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::::finish(client_registration_finish_result.message).serialize(); //! # let client_login_start_result = ClientLogin::::start( -//! # &mut OsRng, +//! # &mut UnwrapErr(SysRng), //! # b"password", //! # )?; //! # let password_file = ServerRegistration::::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 = <::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 = <::KeyExchange as KeyExchange>::Group; //! # type Hash = <::KeyExchange as KeyExchange>::Hash; //! # type OprfGroup = <::OprfCs as voprf::CipherSuite>::Group; //! # struct Default; //! # #[cfg(feature = "ristretto255")] //! # impl CipherSuite for Default { -//! # type OprfCs = opaque_ke::Ristretto255; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for Default { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; -//! # type Ksf = opaque_ke::ksf::Identity; +//! # type KeyExchange = opaque_vx::TripleDh; +//! # type Ksf = opaque_vx::ksf::Identity; //! # } //! # #[derive(Debug, thiserror::Error)] //! # #[error("test error")] @@ -1143,9 +1162,9 @@ //! # Ok(<::Sk as DiffieHellman>::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 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::::new_with_key_pair_and_seed(&mut server_rng, keypair, oprf_seed); //! //! // Incoming registration ... //! # let client_registration_start_result = ClientRegistration::::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::::finish(client_registration_finish_result.message).serialize(); //! # let client_login_start_result = ClientLogin::::start( -//! # &mut OsRng, +//! # &mut UnwrapErr(SysRng), //! # b"password", //! # )?; //! # let password_file = ServerRegistration::::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>( +//! fn hash( //! &self, //! input: GenericArray, -//! ) -> Result, opaque_ke::errors::InternalError> { +//! ) -> Result, opaque_vx::errors::InternalError> { //! let mut output = GenericArray::::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; +//! # type OprfCs = opaque_vx::Ristretto255; +//! # type KeyExchange = opaque_vx::TripleDh; //! # type Ksf = argon2::Argon2<'static>; //! # } //! # #[cfg(not(feature = "ristretto255"))] //! # impl CipherSuite for DefaultCipherSuite { //! # type OprfCs = p256::NistP256; -//! # type KeyExchange = opaque_ke::TripleDh; +//! # type KeyExchange = opaque_vx::TripleDh; //! # type Ksf = argon2::Argon2<'static>; //! # } //! # //! # let password = b"password"; -//! # let mut rng = OsRng; +//! # let mut rng = UnwrapErr(SysRng); //! # let server_setup = ServerSetup::::new(&mut rng); -//! # let mut client_rng = OsRng; +//! # let mut client_rng = UnwrapErr(SysRng); //! # let client_registration_start_result = //! # ClientRegistration::::start(&mut client_rng, password)?; -//! # use opaque_ke::ServerRegistration; +//! # use opaque_vx::ServerRegistration; //! # let server_registration_start_result = ServerRegistration::::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; diff --git a/src/messages.rs b/src/messages.rs index c04c990..1146d16 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -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)] pub struct RegistrationRequest { /// blinded password information - pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) blinded_element: BlindedElement, } /// The answer sent by the server to the user, upon reception of the @@ -64,10 +65,11 @@ pub struct RegistrationRequest { )) )] #[derive_where(Clone)] -#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, as Group>::Pk)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, as Group>::Pk +)] pub struct RegistrationResponse { /// The server's oprf output - pub(crate) evaluation_element: voprf::EvaluationElement, + pub(crate) evaluation_element: EvaluationElement, /// Server's static public key pub(crate) server_s_pk: PublicKey>, } @@ -111,7 +113,7 @@ pub struct RegistrationUpload { ::KE1Message, )] pub struct CredentialRequest { - pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) blinded_element: BlindedElement, pub(crate) ke1_message: ::KE1Message, } @@ -136,7 +138,7 @@ pub struct CredentialRequest { )] pub struct ServerLoginBuilder<'a, CS: CipherSuite, SK: Clone> { pub(crate) server_s_sk: SK, - pub(crate) evaluation_element: voprf::EvaluationElement, + pub(crate) evaluation_element: EvaluationElement, pub(crate) masking_nonce: Zeroizing>, pub(crate) masked_response: MaskedResponse, #[cfg(test)] @@ -184,12 +186,12 @@ impl ServerLoginBuilder<'_, CS, SK> { #[derive_where(Clone)] #[derive_where( Debug, Eq, Hash, PartialEq; - voprf::EvaluationElement, + EvaluationElement, ::KE2Message, )] pub struct CredentialResponse { /// the server's oprf output - pub(crate) evaluation_element: voprf::EvaluationElement, + pub(crate) evaluation_element: EvaluationElement, pub(crate) masking_nonce: GenericArray, pub(crate) masked_response: MaskedResponse, pub(crate) ke2_message: ::KE2Message, @@ -225,19 +227,19 @@ pub type RegistrationRequestLen = as voprf::Grou impl RegistrationRequest { /// Only used for testing purposes #[cfg(test)] - pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { + pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement { self.blinded_element.clone() } /// Serialization into bytes - pub fn serialize(&self) -> GenericArray> { + pub fn serialize(&self) -> Array> { as voprf::Group>::serialize_elem(self.blinded_element.value()) } /// Deserialization from bytes pub fn deserialize(input: &[u8]) -> Result { Ok(Self { - blinded_element: voprf::BlindedElement::deserialize(input)?, + blinded_element: BlindedElement::deserialize(input)?, }) } } @@ -251,11 +253,14 @@ impl RegistrationResponse { pub fn serialize(&self) -> GenericArray> where // RegistrationResponse: KgPk + KePk - as voprf::Group>::ElemLen: Add< as Group>::PkLen>, - RegistrationResponseLen: ArrayLength, + as voprf::Group>::ElemLen: Add< as Group>::PkLen> + ArrayLength, + RegistrationResponseLen: ArrayLength, { - as voprf::Group>::serialize_elem(self.evaluation_element.value()) - .concat(self.server_s_pk.serialize()) + let elem = GenericArray::from_ha0_4( as voprf::Group>::serialize_elem( + self.evaluation_element.value(), + )); + + elem.concat(self.server_s_pk.serialize()) } /// Deserialization from bytes @@ -277,7 +282,7 @@ impl RegistrationResponse { beta: 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 RegistrationUpload { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: 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 { 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( + pub(crate) fn dummy( rng: &mut R, server_setup: &ServerSetup, ) -> Self { @@ -338,11 +346,14 @@ impl CredentialRequest { where ::KE1Message: Serialize, // CredentialRequest: KgPk + Ke1Message - as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + as voprf::Group>::ElemLen: Add> + ArrayLength, + CredentialRequestLen: ArrayLength, { - as voprf::Group>::serialize_elem(self.blinded_element.value()) - .concat(self.ke1_message.serialize()) + let elem = GenericArray::from_ha0_4( as voprf::Group>::serialize_elem( + self.blinded_element.value(), + )); + + elem.concat(self.ke1_message.serialize()) } /// Deserialization from bytes @@ -372,7 +383,7 @@ impl CredentialRequest { /// Only used for testing purposes #[cfg(test)] - pub(crate) fn get_blinded_element_for_testing(&self) -> voprf::BlindedElement { + pub(crate) fn get_blinded_element_for_testing(&self) -> BlindedElement { self.blinded_element.clone() } } @@ -390,18 +401,25 @@ impl CredentialResponse { where ::KE2Message: Serialize, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse - as voprf::Group>::ElemLen: Add, + as voprf::Group>::ElemLen: Add + ArrayLength, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { - 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( 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 CredentialResponse { ::KE2Message: Deserialize, { let evaluation_element = EvaluationElement::deserialize(input)?; - input = &input[voprf::EvaluationElementLen::::USIZE..]; + input = &input[EvaluationElementLen::::USIZE..]; Ok(Self { evaluation_element, @@ -438,7 +456,7 @@ impl CredentialResponse { beta: 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(), diff --git a/src/opaque.rs b/src/opaque.rs index 9ccdadd..f3f7072 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -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; as Group>::Pk, as Group>::Sk, SK, OS)] +#[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; as Group>::Pk, as Group>::Sk, SK, OS +)] pub struct ServerSetup< CS: CipherSuite, SK: Clone = PrivateKey>, @@ -94,8 +94,8 @@ pub struct ServerSetup< voprf::BlindedElement, )] pub struct ClientRegistration { - pub(crate) oprf_client: voprf::OprfClient, - pub(crate) blinded_element: voprf::BlindedElement, + pub(crate) oprf_client: OprfClient, + pub(crate) blinded_element: BlindedElement, } /// The state elements the server holds to record a registration @@ -130,7 +130,7 @@ pub struct ServerRegistration(pub(crate) RegistrationUpload CredentialRequest, )] pub struct ClientLogin { - pub(crate) oprf_client: voprf::OprfClient, + pub(crate) oprf_client: OprfClient, pub(crate) ke1_state: ::KE1State, pub(crate) credential_request: CredentialRequest, } @@ -160,7 +160,7 @@ pub struct ServerLogin { impl ServerSetup>> { /// Generate a new instance of server setup - pub fn new(rng: &mut R) -> Self { + pub fn new(rng: &mut R) -> Self { let keypair = KeyPair::random(rng); Self::new_with_key_pair(rng, keypair) } @@ -179,7 +179,7 @@ impl ServerSetup { /// 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( + pub fn new_with_key_pair_and_seed( rng: &mut R, keypair: KeyPair, SK>, oprf_seed: OS, @@ -211,13 +211,13 @@ impl ServerSetup { OS: OprfSeedSerialization, SK::Error>, // ServerSetup: Hash + KeSk + KePk OS::Len: Add, - Sum: ArrayLength + Add< as Group>::PkLen>, - ServerSetupLen: ArrayLength, + Sum: ArrayLength + Add< as Group>::PkLen>, + ServerSetupLen: 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 ServerSetup { /// 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( + pub fn new_with_key_pair( rng: &mut R, keypair: KeyPair, SK>, ) -> Self { - let mut oprf_seed = GenericArray::default(); + let mut oprf_seed = Output::>::default(); rng.fill_bytes(&mut oprf_seed); Self::new_with_key_pair_and_seed(rng, keypair, OprfSeed(oprf_seed)) @@ -282,12 +282,13 @@ impl ClientRegistration { pub fn serialize(&self) -> GenericArray> where // ClientRegistration: KgSk + KgPk - as voprf::Group>::ScalarLen: Add< as voprf::Group>::ElemLen>, - ClientRegistrationLen: ArrayLength, + as voprf::Group>::ScalarLen: + Add< as voprf::Group>::ElemLen> + ArrayLength, + as voprf::Group>::ElemLen: ArrayLength, + ClientRegistrationLen: 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 ClientRegistration { /// Returns an initial "blinded" request to send to the server, as well as a /// [`ClientRegistration`] - pub fn start( + pub fn start( blinding_factor_rng: &mut R, password: &[u8], ) -> Result, ProtocolError> { @@ -325,7 +326,7 @@ impl ClientRegistration { /// "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( + pub fn finish( self, rng: &mut R, password: &[u8], @@ -357,7 +358,7 @@ impl ClientRegistration { let result = Envelope::::seal( rng, - randomized_pwd_hasher, + &randomized_pwd_hasher, ®istration_response.server_s_pk, params.identifiers, )?; @@ -390,8 +391,8 @@ impl ServerRegistration { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { self.0.serialize() @@ -449,7 +450,7 @@ impl ServerRegistration { } // Creates a dummy instance used for faking a [CredentialResponse] - pub(crate) fn dummy( + pub(crate) fn dummy( rng: &mut R, server_setup: &ServerSetup, ) -> Self { @@ -470,18 +471,17 @@ impl ClientLogin { // CredentialRequest: KgPk + Ke1Message ::KE1Message: Serialize, as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as voprf::Group>::ScalarLen: Add>, ::KE1State: Serialize, Sum< as voprf::Group>::ScalarLen, CredentialRequestLen>: - ArrayLength + Add>, - ClientLoginLen: ArrayLength, + ArrayLength + Add>, + ClientLoginLen: 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 ClientLogin { impl ClientLogin { /// Returns an initial "blinded" password request to send to the server, as /// well as a [`ClientLogin`] - pub fn start( + pub fn start( rng: &mut R, password: &[u8], ) -> Result, ProtocolError> { @@ -528,7 +528,7 @@ impl ClientLogin { /// "Unblinds" the server's answer and returns the opened assets from the /// server - pub fn finish( + pub fn finish( self, rng: &mut R, password: &[u8], @@ -570,7 +570,7 @@ impl ClientLogin { let opened_envelope = envelope .open( - randomized_pwd_hasher, + &randomized_pwd_hasher, server_s_pk.clone(), params.identifiers, ) @@ -641,7 +641,7 @@ impl ServerLogin { /// /// 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, key_material: GenericArray as voprf::Group>::ScalarLen>, @@ -668,7 +668,7 @@ impl ServerLogin { 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 ServerLogin { /// 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, password_file: Option>, @@ -747,7 +747,7 @@ impl ServerLogin { 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 ServerLogin { #[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( + pub fn start( rng: &mut R, server_setup: &ServerSetup, password_file: Option>, @@ -1004,21 +1004,22 @@ pub struct ServerLoginStartResult { #[allow(clippy::type_complexity)] fn get_password_derived_key( input: &[u8], - oprf_client: voprf::OprfClient, + oprf_client: OprfClient, evaluation_element: voprf::EvaluationElement, ksf: Option<&CS::Ksf>, -) -> Result<(Output>, Hkdf>), ProtocolError> { +) -> Result<(Output>, hkdf::SimpleHkdf>), 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::>::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( fn oprf_key_from_key_material( input: GenericArray as voprf::Group>::ScalarLen>, ) -> Result as voprf::Group>::ScalarLen>, InternalError> { - Ok(OprfGroup::::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::::serialize_scalar( + voprf::derive_key::(&input, STR_OPAQUE_DERIVE_KEY_PAIR, voprf::Mode::Oprf)?, + ))) } #[cfg_attr( @@ -1066,19 +1063,28 @@ pub(crate) type MaskedResponseLen = impl MaskedResponse { pub(crate) fn serialize(&self) -> GenericArray> { - self.nonce.concat_ext(&self.hash).concat(self.pk.clone()) - } + let hash_ga: &GenericArray>> = + 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 { Ok(Self { nonce: bytes.take_array("masked nonce")?, - hash: bytes.take_array("masked hash")?, + hash: bytes + .take_array::>>("masked hash")? + .into_ha0_4(), pk: bytes.take_array("masked public key")?, }) } pub(crate) fn iter(&self) -> impl Clone + Iterator { - [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( *x1 ^= x2 } - MaskedResponse::deserialize_take(&mut (xor_pad.as_slice())) + let mut slice: &[u8] = &xor_pad; + + MaskedResponse::deserialize_take(&mut (slice)) } fn unmask_response( @@ -1124,7 +1132,7 @@ fn unmask_response( *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( /// 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( +fn blind( rng: &mut R, password: &[u8], ) -> Result, 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( break scalar; } }; - voprf::OprfClient::deterministic_blind_unchecked(password, blind)? + OprfClient::deterministic_blind_unchecked(password, blind)? }; Ok(result) diff --git a/src/serialization/mod.rs b/src/serialization/mod.rs index 2cff22d..b534636 100644 --- a/src/serialization/mod.rs +++ b/src/serialization/mod.rs @@ -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>( - input: usize, -) -> Result, ProtocolError> { - const SIZEOF_USIZE: usize = core::mem::size_of::(); +pub(crate) fn i2osp(input: usize) -> Result, ProtocolError> { + const SIZEOF_USIZE: usize = size_of::(); // 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>( // Corresponds to the OS2IP() function from RFC8017 #[cfg(test)] pub(crate) fn os2ip(input: &[u8]) -> Result { - if input.len() > core::mem::size_of::() { + if input.len() > size_of::() { return Err(ProtocolError::SerializationError); } - let mut output_array = [0u8; core::mem::size_of::()]; - output_array[core::mem::size_of::() - input.len()..].copy_from_slice(input); + let mut output_array = [0u8; size_of::()]; + output_array[size_of::() - input.len()..].copy_from_slice(input); Ok(usize::from_be_bytes(output_array)) } @@ -69,14 +67,14 @@ impl UpdateExt for T { } pub(crate) trait SliceExt { - fn take_array>( + fn take_array( self: &mut &Self, name: &'static str, ) -> Result, ProtocolError>; } impl SliceExt for [u8] { - fn take_array>( + fn take_array( self: &mut &Self, name: &'static str, ) -> Result, 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 = Array::try_from(front).unwrap(); + Ok(GenericArray::from(arr)) } } -pub(crate) trait GenericArrayExt> { - type Output: ArrayLength; +pub(crate) trait GenericArrayExt { + 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) -> GenericArray; } -impl, O: ArrayLength> GenericArrayExt for GenericArray +impl GenericArrayExt for GenericArray where O: Add, - Sum: ArrayLength, + Sum: ArrayLength, { type Output = Sum; @@ -119,6 +118,23 @@ where } } +pub(crate) trait ConcatExt: Sized { + fn cat(self, other: GenericArray) -> GenericArray> + where + N: Add, + Sum: ArrayLength; +} + +impl ConcatExt for GenericArray { + fn cat(self, other: GenericArray) -> GenericArray> + where + N: Add, + Sum: ArrayLength, + { + Concat::concat(self, other) + } +} + #[cfg(test)] mod tests; diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs index f71a20f..8fbf2b0 100644 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -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; - 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; - 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; + 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; + 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; + 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, ::p256::NistP256, sha2::Sha256>; - type Ksf = crate::ksf::Identity; + type OprfCs = p256::NistP256; + type KeyExchange = SigmaI, 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, ::p384::NistP384, sha2::Sha384>; - type Ksf = crate::ksf::Identity; + type OprfCs = p384::NistP384; + type KeyExchange = SigmaI, 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, 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, Ristretto255, sha2::Sha512>; - type Ksf = crate::ksf::Identity; + type Ksf = ksf::Identity; } #[cfg(feature = "ecdsa")] fn random_point() -> as Group>::Pk { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let sk = KeGroup::::random_sk(&mut rng); KeGroup::::public_key(&sk) } fn random_element() -> as voprf::Group>::Elem { - let mut rng = OsRng; - let scalar = OprfGroup::::random_scalar(&mut rng); + let mut rng = UnwrapErr(SysRng); + let scalar = OprfGroup::::random_scalar(&mut rng).unwrap(); OprfGroup::::base_elem() * &scalar } @@ -139,10 +138,10 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> { where // ClientRegistration: KgSk + KgPk as voprf::Group>::ScalarLen: Add< as voprf::Group>::ElemLen>, - ClientRegistrationLen: ArrayLength, + ClientRegistrationLen: ArrayLength, { let pw = b"hunter2"; - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let blind_result = &voprf::OprfClient::::blind(pw, &mut rng)?; @@ -186,12 +185,12 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: 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::>::default(); rng.fill_bytes(&mut masking_key); @@ -287,11 +286,11 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> { where // RegistrationResponse: KgPk + KePk as voprf::Group>::ElemLen: Add< as Group>::PkLen>, - RegistrationResponseLen: ArrayLength, + RegistrationResponseLen: ArrayLength, { let elem = random_element::(); let beta_bytes = OprfGroup::::serialize_elem(elem); - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let skp = KeyPair::>::derive_random(&mut rng); let pubkey_bytes = skp.public().serialize(); @@ -345,10 +344,10 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let skp = KeyPair::>::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::>::default(); rng.fill_bytes(&mut masking_key); - let randomized_pwd_hasher = hkdf::Hkdf::new(None, &key); + let randomized_pwd_hasher = hkdf::SimpleHkdf::>::new(None, &key); let (envelope, _, _) = Envelope::::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> { ::KE1Message: Deserialize + Serialize, // CredentialRequest: KgPk + Ke1Message as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let alpha = random_element::(); let alpha_bytes = OprfGroup::::serialize_elem(alpha); @@ -466,17 +465,17 @@ fn triple_dh_credential_response_roundtrip() -> Result<(), ProtocolError> { // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { let elem = random_element::(); let elem_bytes = OprfGroup::::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::::deserialize(&input).unwrap(); + let l2 = CredentialResponse::::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 as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { let pt = random_point::(); let pt_bytes = KeGroup::::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 ::KE3Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); @@ -661,7 +660,7 @@ fn sigma_i_ecdsa_credential_finalization_roundtrip() -> Result<(), ProtocolError where ::KE3Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let r = KeGroup::::serialize_sk(&KeGroup::::random_sk(&mut rng)); let s = KeGroup::::serialize_sk(&KeGroup::::random_sk(&mut rng)); @@ -696,16 +695,16 @@ fn triple_dh_client_login_roundtrip() -> Result<(), ProtocolError> { // CredentialRequest: KgPk + Ke1Message ::KE1Message: Serialize, as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as voprf::Group>::ScalarLen: Add>, ::KE1State: Serialize, Sum< as voprf::Group>::ScalarLen, CredentialRequestLen>: - ArrayLength + Add>, - ClientLoginLen: ArrayLength, + ArrayLength + Add>, + ClientLoginLen: ArrayLength, { let pw = b"hunter2"; - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let client_e_kp = KeyPair::>::derive_random(&mut rng); let mut client_nonce = [0; NonceLen::USIZE]; @@ -762,7 +761,7 @@ fn triple_dh_ke1_message_roundtrip() -> Result<(), ProtocolError> { where ::KE1Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let client_e_kp = KeyPair::>::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 ::KE2Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let server_e_kp = KeyPair::>::derive_random(&mut rng); let mut mac = Output::>::default(); @@ -839,7 +838,7 @@ fn sigma_i_ecdsa_ke2_message_roundtrip() -> Result<(), ProtocolError> { where ::KE2Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let server_e_kp = KeyPair::>::derive_random(&mut rng); let mut mac = Output::>::default(); @@ -878,7 +877,7 @@ fn triple_dh_ke3_message_roundtrip() -> Result<(), ProtocolError> { where ::KE3Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let mut mac = Output::>::default(); rng.fill_bytes(&mut mac); @@ -910,7 +909,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> { where ::KE3Message: Deserialize + Serialize, { - let mut rng = OsRng; + let mut rng = UnwrapErr(SysRng); let r = KeGroup::::serialize_sk(&KeGroup::::random_sk(&mut rng)); let s = KeGroup::::serialize_sk(&KeGroup::::random_sk(&mut rng)); let mut mac = Output::>::default(); @@ -934,7 +933,7 @@ fn sigma_i_ecdsa_ke3_message_roundtrip() -> Result<(), ProtocolError> { proptest! { #[test] - fn test_i2osp_os2ip(bytes in vec(any::(), 0..core::mem::size_of::())) { + fn test_i2osp_os2ip(bytes in vec(any::(), 0..size_of::())) { use generic_array::typenum::{U0, U1, U2, U3, U4, U5, U6, U7}; let input = os2ip(&bytes).unwrap(); diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs index 1afc333..7768983 100644 --- a/src/tests/full_test.rs +++ b/src/tests/full_test.rs @@ -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::*; @@ -70,7 +72,7 @@ macro_rules! ciphersuite_types { macro_rules! generate { ($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($output:ident)) => { - paste::paste! { + pastey::paste! { $(#[$attr])* { let parameters = generate_parameters::<$name>()?; @@ -89,7 +91,7 @@ macro_rules! generate { macro_rules! run_all { ($(#[$attr:meta])* $name:ident, $oprf:ty, $ke:ty, ($fn:ident $(, $par:expr)*)) => { - paste::paste! { + pastey::paste! { $(#[$attr])* $fn::<$name>(super::full_test_vectors::[] $(, $par)*)?; } @@ -118,7 +120,7 @@ macro_rules! oprf_ciphersuites { #[$ke_attr_1:meta] #[$ke_attr_2:meta] [$ke_name:ident, $ke:ty], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], ) => { - paste::paste! { + pastey::paste! { $($macro!(#[$ke_attr_1] #[$ke_attr_2] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ } }; @@ -127,7 +129,7 @@ macro_rules! oprf_ciphersuites { #[$ke_attr:meta] [$ke_name:ident, $ke:ty], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], ) => { - paste::paste! { + pastey::paste! { $($macro!(#[$ke_attr] $(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ } }; @@ -136,7 +138,7 @@ macro_rules! oprf_ciphersuites { [$ke_name:ident, $ke:ty], [$($(#[$oprf_attr:meta])? [$oprf_name:ident, $oprf:ty$(,)?]),+$(,)?], ) => { - paste::paste! { + pastey::paste! { $($macro!($(#[$oprf_attr])? [<$oprf_name $ke_name>], $oprf, $ke, $par);)+ } } @@ -196,7 +198,7 @@ macro_rules! sigma_i_ciphersuites { $macro:ident!$par:tt => [$($(#[$sig_attr:meta])? [$sig_name:ident, $sig:ty]),+$(,)?], ) => { - paste::paste! { + pastey::paste! { $( oprf_ciphersuites!( $macro!$par => [ @@ -261,10 +263,6 @@ pub struct TestVectorParameters { static STR_PASSWORD: &str = "password"; -fn decode(values: &Value, key: &str) -> Option> { - 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 ::KE3Message: Serialize, // ClientRegistration: KgSk + KgPk as voprf::Group>::ScalarLen: Add< as voprf::Group>::ElemLen>, - ClientRegistrationLen: ArrayLength, + ClientRegistrationLen: ArrayLength, // RegistrationResponse: KgPk + KePk as voprf::Group>::ElemLen: Add< as Group>::PkLen>, - RegistrationResponseLen: ArrayLength, + RegistrationResponseLen: ArrayLength, // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload // CredentialRequest: KgPk + Ke1Message ::KE1Message: Serialize, as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as voprf::Group>::ScalarLen: Add>, ::KE1State: Serialize, Sum< as voprf::Group>::ScalarLen, CredentialRequestLen>: - ArrayLength + Add>, - ClientLoginLen: ArrayLength, + ArrayLength + Add>, + ClientLoginLen: ArrayLength, // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: 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::::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 = as voprf::Group>::random_scalar(&mut rng); + let blinding_factor = as voprf::Group>::random_scalar(&mut rng)?; let blinding_factor_bytes = OprfGroup::::serialize_scalar(blinding_factor); let mut blinding_factor_registration_rng = CycleRng::new(blinding_factor_bytes.to_vec()); let client_registration_start_result = - ClientRegistration::::start(&mut blinding_factor_registration_rng, password).unwrap(); + ClientRegistration::::start(&mut blinding_factor_registration_rng, password)?; let blinding_factor_bytes_returned = OprfGroup::::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 = 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::::start(&mut client_login_start_rng, password).unwrap(); + ClientLogin::::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 as voprf::Group>::ScalarLen: Add< as voprf::Group>::ElemLen>, - ClientRegistrationLen: ArrayLength, + ClientRegistrationLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); let mut rng = CycleRng::new(parameters.blinding_factor.to_vec()); @@ -822,14 +812,16 @@ fn test_serialization() -> Result<(), ProtocolError> { ClientRegistration::::start(&mut rng, ¶meters.password)?; // Test the bincode serialization (binary). + let cfg = bincode_next::config::standard(); let registration_request = - bincode::serialize(&client_registration_start_result.message).unwrap(); + bincode_next::serde::encode_to_vec(&client_registration_start_result.message, cfg) + .unwrap(); assert_eq!( registration_request.len(), RegistrationRequestLen::::USIZE ); - let registration_request: RegistrationRequest = - bincode::deserialize(®istration_request).unwrap(); + let (registration_request, _): (RegistrationRequest, usize) = + bincode_next::serde::decode_from_slice(®istration_request, cfg).unwrap(); assert_eq!( hex::encode(client_registration_start_result.message.serialize()), hex::encode(registration_request.serialize()), @@ -852,7 +844,7 @@ fn test_registration_response() -> Result<(), ProtocolError> { where // RegistrationResponse: KgPk + KePk as voprf::Group>::ElemLen: Add< as Group>::PkLen>, - RegistrationResponseLen: ArrayLength, + RegistrationResponseLen: ArrayLength, { let parameters = populate_test_vectors( &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, @@ -894,8 +886,8 @@ fn test_registration_upload() -> Result<(), ProtocolError> { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, { let parameters = populate_test_vectors( &serde_json::from_str(test_vector).map_err(|_| ProtocolError::SerializationError)?, @@ -945,8 +937,8 @@ fn test_password_file() -> Result<(), ProtocolError> { // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -977,13 +969,13 @@ fn test_credential_request() -> Result<(), ProtocolError> { // CredentialRequest: KgPk + Ke1Message ::KE1Message: Serialize, as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, // ClientLogin: KgSk + CredentialRequest + Ke1State as voprf::Group>::ScalarLen: Add>, ::KE1State: Serialize, Sum< as voprf::Group>::ScalarLen, CredentialRequestLen>: - ArrayLength + Add>, - ClientLoginLen: ArrayLength, + ArrayLength + Add>, + ClientLoginLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -1024,12 +1016,12 @@ fn test_credential_response() -> Result<(), ProtocolError> { // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { let parameters = populate_test_vectors(&serde_json::from_str(test_vector).unwrap()); @@ -1182,8 +1174,8 @@ fn test_complete_flow( 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::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, registration_password)?; @@ -1330,8 +1322,8 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { fn inner(_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::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, password)?; @@ -1377,8 +1369,8 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> { fn inner(_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::::new(&mut server_rng); let client_registration_start_result = ClientRegistration::::start(&mut client_rng, password)?; diff --git a/src/tests/mock_rng.rs b/src/tests/mock_rng.rs index e3d2394..fe1ce62 100644 --- a/src/tests/mock_rng.rs +++ b/src/tests/mock_rng.rs @@ -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(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 { + 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 { + 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 {} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index df0d17e..f3a1632 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -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> { + values[key].as_str().and_then(|s| hex::decode(s).ok()) +} diff --git a/src/tests/parser.rs b/src/tests/parser.rs index 920dd45..83d77d1 100644 --- a/src/tests/parser.rs +++ b/src/tests/parser.rs @@ -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.+?) Test Vectors").unwrap(); + let re = regex::Regex::new(r" {2}(?P.+?) 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.*?)\n(.|\n)*?Group: (?P.*?)\n", + r" Configuration\n([\s\S])*?OPRF: (?P.*?)\n([\s\S])*?Group: (?P.*?)\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") diff --git a/src/tests/test_opaque_vectors.rs b/src/tests/test_opaque_vectors.rs index dbd145e..0c56b02 100644 --- a/src/tests/test_opaque_vectors.rs +++ b/src/tests/test_opaque_vectors.rs @@ -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> { - values[key].as_str().and_then(|s| hex::decode(s).ok()) -} - fn populate_test_vectors(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::::serialize_sk(&KeGroup::::random_sk(&mut OsRng)).to_vec(), - } + decode(values, "client_public_key").unwrap_or_else(|| { + KeGroup::::serialize_sk(&KeGroup::::random_sk(&mut UnwrapErr(SysRng))) + .to_vec() + }) }, dummy_masking_key: { match decode(values, "masking_key") { @@ -151,8 +148,8 @@ where // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { let password_file = ServerRegistration::::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; + type OprfCs = Ristretto255; + type KeyExchange = TripleDh; type Ksf = Identity; } @@ -331,7 +330,7 @@ fn test_registration_response( where // RegistrationResponse: KgPk + KePk as voprf::Group>::ElemLen: Add< as Group>::PkLen>, - RegistrationResponseLen: ArrayLength, + RegistrationResponseLen: ArrayLength, { for parameters in tvs { let server_setup = ServerSetup::::deserialize( @@ -370,8 +369,8 @@ where // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, { for parameters in tvs { let mut rng = CycleRng::new(parameters.blind_registration.to_vec()); @@ -417,7 +416,7 @@ where // CredentialRequest: KgPk + Ke1Message ::KE1Message: Serialize, as voprf::Group>::ElemLen: Add>, - CredentialRequestLen: ArrayLength, + CredentialRequestLen: ArrayLength, { for parameters in tvs { let client_login_start = [ @@ -444,18 +443,18 @@ where // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { for parameters in tvs { let server_setup = ServerSetup::::deserialize( @@ -530,7 +529,7 @@ where ClientLogin::::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::::deserialize(¶meters.KE2)?, ClientLoginFinishParameters::new( @@ -576,8 +575,8 @@ where // RegistrationUpload: (KePk + Hash) + Envelope as Group>::PkLen: Add>>, Sum< as Group>::PkLen, OutputSize>>: - ArrayLength + Add>, - RegistrationUploadLen: ArrayLength, + ArrayLength + Add>, + RegistrationUploadLen: ArrayLength, // ServerRegistration = RegistrationUpload { for parameters in tvs { @@ -644,12 +643,12 @@ where // CredentialResponseWithoutKeLen: (KgPk + Nonce) + MaskedResponse as voprf::Group>::ElemLen: Add, Sum< as voprf::Group>::ElemLen, NonceLen>: - ArrayLength + Add>, - CredentialResponseWithoutKeLen: ArrayLength, + ArrayLength + Add>, + CredentialResponseWithoutKeLen: ArrayLength, // CredentialResponse: CredentialResponseWithoutKeLen + Ke2Message ::KE2Message: Serialize, CredentialResponseWithoutKeLen: Add>, - CredentialResponseLen: ArrayLength, + CredentialResponseLen: ArrayLength, { for parameters in tvs { let server_setup = ServerSetup::::deserialize( diff --git a/tests/migration.rs b/tests/migration.rs deleted file mode 100644 index 7cfeb43..0000000 --- a/tests/migration.rs +++ /dev/null @@ -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; - type Ksf = Identity; -} - -#[test] -fn registration_upload() { - // V3 registration. - let result = v3ClientRegistration::::start(&mut OsRng, PASSWORD).unwrap(); - let client = result.state; - - let old_server_setup = v3ServerSetup::::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 = <<::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; - type OldSkLen = <::KeGroup as v3KeGroup>::SkLen; - let (old_serialied_rest, old_fake_keypair_serialized): ( - GenericArray>, - _, - ) = old_serialized.split(); - let old_fake_keypair = - KeyPair::<::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::::deserialize(&new_serialized).unwrap() - }; - - // `ServerRegistration` migration. - let old_registration_serialized = old_registration.serialize(); - let registration = - ServerRegistration::::deserialize(&old_registration_serialized).unwrap(); - - // Check if new `ServerRegistration` still works. - let result = ClientLogin::::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(); -} diff --git a/tests/remote_key.rs b/tests/remote_key.rs index f64398b..13a9161 100644 --- a/tests/remote_key.rs +++ b/tests/remote_key.rs @@ -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;