From dc8246f20d45402e6bd100ffc25a108b4b620038 Mon Sep 17 00:00:00 2001 From: Kevin Lewi Date: Wed, 9 Oct 2024 20:26:16 -0700 Subject: [PATCH] Updating v2 with latest voprf (v0.4.1) release (#366) * Fix Clippy (#289) * Add Dependabot (#287) * Fix Clippy * Add Dependabot * Bump actions/checkout from 2 to 3 (#291) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/cache from 2 to 3 (#292) Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update dependencies (#288) * Fix Clippy * Update dependencies * Fix CI (#298) * Rename X25519 to Curve25519 (#302) * Update `curve25519-dalek` to 4.0.0-pre.5 (#301) * Update `curve25519-dalek` * Improve documentation * Update `voprf` to 0.5.0-pre.1 * Bump `voprf` to v0.5.0-pre.2 (#304) * Only use explicit crate features (#306) * Publishing v3.0.0-pre.1 (#309) * Update `rustyline` to v0.11 (#313) * Update VOPRF to draft 19 (#307) * Update `argon2` to v0.5 (#314) * Test P-384 (#290) * Update scrypt requirement from 0.10 to 0.11 (#315) Updates the requirements on [scrypt](https://github.com/RustCrypto/password-hashes) to permit the latest version. - [Release notes](https://github.com/RustCrypto/password-hashes/releases) - [Commits](https://github.com/RustCrypto/password-hashes/compare/scrypt-v0.10.0...scrypt-v0.11.0) --- updated-dependencies: - dependency-name: scrypt dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Publishing v3.0.0-pre.2 (#318) * Bump `voprf` to v0.5.0-pre.4 (#322) * Correctly clamp Curve25519 secret keys (#323) * Curve25519 test vectors (#319) * Curve25519 test vectors * Adjust `derive_auth_keypair()` for Curve25519 * Update test vectors * Fix Curve25519 random scalar generation Co-Authored-By: Kevin Lewi * Update test vectors * Update test vectors * Update test vectors --------- Co-authored-by: Kevin Lewi * Updating dual-license language (#324) * Update criterion requirement from 0.4 to 0.5 (#325) Updates the requirements on [criterion](https://github.com/bheisler/criterion.rs) to permit the latest version. - [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/bheisler/criterion.rs/compare/0.4.0...0.5.0) --- updated-dependencies: - dependency-name: criterion dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update keypair generation to use derive_auth_keypair (#326) * Fixing simple_login test to enable argon2 feature (#328) * Publishing v3.0.0-pre.3 (#327) * Update rustyline requirement from 11 to 12 (#332) Updates the requirements on [rustyline](https://github.com/kkawakam/rustyline) to permit the latest version. - [Release notes](https://github.com/kkawakam/rustyline/releases) - [Changelog](https://github.com/kkawakam/rustyline/blob/master/History.md) - [Commits](https://github.com/kkawakam/rustyline/compare/v11.0.0...v12.0.0) --- updated-dependencies: - dependency-name: rustyline dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * update parameter from sk to private_key (#329) * Bump `curve25519-dalek` to v4.0.0-rc.3 (#330) * add more resources (WebAssembly and React Native) (#335) * add more resources (WebAssembly and React Native) * Fixing clippy --------- Co-authored-by: Kevin Lewi * Publishing v3.0.0-pre.4 (#337) * update docs: clarify export_key and session_key length (#338) * Increase MSRV to 1.70 and update workflow dependencies (#342) * Clarifying the persisting of server setup (#344) * Add `clippy::doc_markdown` (#346) * Fixing clippy errors (#347) * Test P-521 (#349) * Test P-521 * De-duplicate generic calls * Simplify full test vectors generation * Adding copyright header to generated test file (#351) * Update rustyline requirement from 12 to 13 (#352) Updates the requirements on [rustyline](https://github.com/kkawakam/rustyline) to permit the latest version. - [Release notes](https://github.com/kkawakam/rustyline/releases) - [Changelog](https://github.com/kkawakam/rustyline/blob/master/History.md) - [Commits](https://github.com/kkawakam/rustyline/compare/v12.0.0...v13.0.0) --- updated-dependencies: - dependency-name: rustyline dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump actions/cache from 3 to 4 (#354) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Updating dependencies (#360) * docs: add details for client login final step (#358) This tweaks the documentation on the main module, in order to add some details on the outcome of the client login final step. In particular, it clarifies the result of `ClientLogin::finish()` both on success and on errors and it adds some intra-crate links to the relevant structures and fields. * Publishing v3.0.0-pre.5 (#364) * Revert "Update keypair generation to use derive_auth_keypair (#326)" This reverts commit deb7ca3dc0984e7e7c52b86c7cdfca85b7036d41. * Fixups to keep in sync with draft-10 --------- Signed-off-by: dependabot[bot] Co-authored-by: daxpedda Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nik Graf Co-authored-by: Luca Bruno --- .cargo/license.rs | 9 +- .github/dependabot.yml | 12 + .github/workflows/main.yml | 74 +++--- .github/workflows/publish.yml | 5 +- CHANGELOG.md | 3 + CONTRIBUTING.md | 3 +- Cargo.toml | 65 ++--- LICENSE | 12 - README.md | 14 +- benches/opaque.rs | 127 +++++----- examples/digital_locker.rs | 32 ++- examples/simple_login.rs | 18 +- scripts/digital_locker.exp | 9 +- scripts/simple_login.exp | 11 +- src/ciphersuite.rs | 11 +- src/envelope.rs | 21 +- src/errors.rs | 14 +- src/hash.rs | 23 +- .../group/{x25519.rs => curve25519.rs} | 42 ++-- src/key_exchange/group/elliptic_curve.rs | 29 +-- src/key_exchange/group/mod.rs | 42 ++-- src/key_exchange/group/ristretto255.rs | 40 ++-- src/key_exchange/mod.rs | 9 +- src/key_exchange/traits.rs | 9 +- src/key_exchange/tripledh.rs | 21 +- src/keypair.rs | 39 +-- src/ksf.rs | 15 +- src/lib.rs | 199 ++++++++-------- src/messages.rs | 60 ++--- src/opaque.rs | 87 +++---- src/serialization/mod.rs | 25 +- src/serialization/tests.rs | 73 ++++-- src/tests/full_test.rs | 223 +++++++++--------- src/tests/mock_rng.rs | 11 +- src/tests/mod.rs | 9 +- src/tests/opaque_vectors.rs | 13 +- src/tests/parser.rs | 9 +- src/tests/test_opaque_vectors.rs | 12 +- src/util.rs | 9 +- 39 files changed, 735 insertions(+), 704 deletions(-) create mode 100644 .github/dependabot.yml delete mode 100644 LICENSE rename src/key_exchange/group/{x25519.rs => curve25519.rs} (68%) diff --git a/.cargo/license.rs b/.cargo/license.rs index 3fa8d9fc..664968be 100644 --- a/.cargo/license.rs +++ b/.cargo/license.rs @@ -1,6 +1,7 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..74b048ac --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 + +updates: + - package-ecosystem: cargo + directory: / + schedule: + interval: daily + + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e92abf85..4d0eb49c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,24 +13,21 @@ jobs: fail-fast: false matrix: backend_feature: - - --features ristretto255-u64,ristretto255-voprf - - --features ristretto255-u32,ristretto255-voprf + - --features ristretto255-voprf - - - --features x25519-u64,ristretto255-u64,ristretto255-voprf - - --features x25519-u32,ristretto255-u32,ristretto255-voprf - - --features x25519-u64 - - --features x25519-u32 + - --features curve25519,ristretto255-voprf + - --features curve25519 frontend_feature: - - --features argon2 - --features serde toolchain: - stable - - 1.57.0 + - 1.74.0 name: test steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: Install ${{ matrix.toolchain }} toolchain uses: actions-rs/toolchain@v1 @@ -61,16 +58,13 @@ jobs: # 32-bit x86 - i686-unknown-linux-gnu backend_feature: - - --features ristretto255-u64,ristretto255-voprf - - --features ristretto255-u32,ristretto255-voprf + - --features ristretto255-voprf - - - x25519-u64,ristretto255-u64,ristretto255-voprf - - x25519-u32,ristretto255-u64,ristretto255-voprf - - x25519-u64 - - x25519-u32 + - curve25519,ristretto255-voprf + - curve25519 steps: - - uses: actions/checkout@v2 - - uses: hecrj/setup-rust-action@v1 + - uses: actions/checkout@main + - uses: hecrj/setup-rust-action@v2 - run: cargo install cross # Note: just use `cross` as you would `cargo`, but always # pass the `--target=${{ matrix.target }}` arg. (Yes, really). @@ -84,13 +78,13 @@ jobs: matrix: toolchain: - stable - - 1.57.0 + - 1.74.0 name: test simple_login command-line example steps: - name: install expect run: sudo apt-get install expect - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: install rust uses: actions-rs/toolchain@v1 with: @@ -107,13 +101,13 @@ jobs: matrix: toolchain: - stable - - 1.57.0 + - 1.74.0 name: test digital_locker command-line example steps: - name: install expect run: sudo apt-get install expect - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: install rust uses: actions-rs/toolchain@v1 with: @@ -135,21 +129,18 @@ jobs: # for any no_std target - thumbv6m-none-eabi backend_feature: - - ristretto255-u64,ristretto255-voprf - - ristretto255-u32,ristretto255-voprf + - ristretto255-voprf - - - x25519-u64,ristretto255-u64,ristretto255-voprf - - x25519-u32,ristretto255-u32,ristretto255-voprf - - x25519-u64 - - x25519-u32 + - curve25519,ristretto255-voprf + - curve25519 frontend_feature: - argon2 - serde steps: - - uses: actions/checkout@v2 - - uses: hecrj/setup-rust-action@v1 + - uses: actions/checkout@main + - uses: hecrj/setup-rust-action@v2 - run: rustup target add ${{ matrix.target }} - - run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }} --features ${{ matrix.backend_feature }} + - run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }},${{ matrix.backend_feature }} benches: name: cargo bench compilation @@ -158,16 +149,13 @@ jobs: fail-fast: false matrix: backend_feature: - - --features ristretto255-u64,ristretto255-voprf - - --features ristretto255-u32,ristretto255-voprf + - --features ristretto255-voprf - - - --features x25519-u64,ristretto255-u64,ristretto255-voprf - - --features x25519-u32,ristretto255-u32,ristretto255-voprf - - --features x25519-u32 - - --features x25519-u32 + - --features curve25519,ristretto255-voprf + - --features curve25519 steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -187,7 +175,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -201,7 +189,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-targets --features argon2,std,x25519-u64 -- -D warnings + args: --all-targets --features argon2,std,curve25519 -- -D warnings - name: Run cargo doc uses: actions-rs/cargo@v1 @@ -209,14 +197,14 @@ jobs: RUSTDOCFLAGS: -D warnings with: command: doc - args: --no-deps --document-private-items --features argon2,std,x25519-u64 + args: --no-deps --document-private-items --features argon2,std,curve25519 format: name: cargo fmt runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: Install nightly toolchain uses: actions-rs/toolchain@v1 @@ -237,7 +225,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: | ~/.cargo/.crates.toml @@ -251,7 +239,7 @@ jobs: run: cargo install taplo-cli --locked - name: Checkout sources - uses: actions/checkout@v2 + uses: actions/checkout@main - name: Run Taplo run: taplo fmt --check @@ -260,5 +248,5 @@ jobs: name: cargo-deny check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@main - uses: EmbarkStudios/cargo-deny-action@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7c9623a8..30aa7419 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,12 +11,13 @@ jobs: strategy: matrix: os: [ubuntu-latest] + rust: [stable] steps: - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 with: rust-version: ${{ matrix.rust }} - - uses: actions/checkout@master + - uses: actions/checkout@main - name: Login to crates.io run: cargo login $CRATES_IO_TOKEN env: diff --git a/CHANGELOG.md b/CHANGELOG.md index ba0938e8..e41fba14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 2.1.0-pre.1 (October 10, 2024) +* Updated dependencies: voprf v0.4.1, curve25519-dalek v4 + ## 2.0.0 (September 21, 2022) * Synced implementation with draft-irtf-cfrg-opaque-10 * Changed argon2 salt length to recommended value (16 bytes) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4043ae6..145a05a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,4 +27,5 @@ 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 the LICENSE file in the root directory of this source tree. +licensed under both the LICENSE-MIT and LICENSE-APACHE files in the root +directory of this source tree. diff --git a/Cargo.toml b/Cargo.toml index 0dea93cc..b874307f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,48 +7,39 @@ keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] license = "Apache-2.0 OR MIT" name = "opaque-ke" readme = "README.md" -repository = "https://github.com/novifinancial/opaque-ke" -rust-version = "1.57" -version = "2.0.0" +repository = "https://github.com/facebook/opaque-ke" +rust-version = "1.74" +version = "2.1.0-pre.1" [features] -default = ["ristretto255-u64", "ristretto255-voprf", "serde"] -ristretto255 = ["curve25519-dalek", "voprf/ristretto255"] -ristretto255-fiat-u32 = ["curve25519-dalek/fiat_u32_backend", "ristretto255"] -ristretto255-fiat-u64 = ["curve25519-dalek/fiat_u64_backend", "ristretto255"] -ristretto255-simd = ["curve25519-dalek/simd_backend", "ristretto255"] -ristretto255-u32 = ["curve25519-dalek/u32_backend", "ristretto255"] -ristretto255-u64 = ["curve25519-dalek/u64_backend", "ristretto255"] +argon2 = ["dep:argon2"] +curve25519 = ["dep:curve25519-dalek"] +default = ["ristretto255-voprf", "serde"] +ristretto255 = ["dep:curve25519-dalek", "voprf/ristretto255"] ristretto255-voprf = ["ristretto255", "voprf/ristretto255-ciphersuite"] -serde = ["serde_", "generic-array/serde", "voprf/serde"] -std = ["getrandom"] -x25519 = ["curve25519-dalek"] -x25519-fiat-u32 = ["curve25519-dalek/fiat_u32_backend", "x25519"] -x25519-fiat-u64 = ["curve25519-dalek/fiat_u64_backend", "x25519"] -x25519-simd = ["curve25519-dalek/simd_backend", "x25519"] -x25519-u32 = ["curve25519-dalek/u32_backend", "x25519"] -x25519-u64 = ["curve25519-dalek/u64_backend", "x25519"] +serde = ["dep:serde", "generic-array/serde", "voprf/serde"] +std = ["dep:getrandom"] [dependencies] -argon2 = { version = "0.4", default-features = false, features = [ +argon2 = { version = "0.5", default-features = false, features = [ "alloc", ], optional = true } -curve25519-dalek = { version = "=4.0.0-pre.1", default-features = false, optional = true } -derive-where = { version = "=1.0.0-rc.3", features = ["zeroize-on-drop"] } +curve25519-dalek = { version = "4", default-features = false, features = [ + "zeroize", +], optional = true } +derive-where = { version = "1", features = ["zeroize-on-drop"] } digest = "0.10" displaydoc = { version = "0.2", default-features = false } -elliptic-curve = { version = "0.12", features = ["hash2curve", "sec1"] } +elliptic-curve = { version = "0.13", features = ["hash2curve", "sec1"] } generic-array = "0.14" hkdf = "0.12" hmac = "0.12" rand = { version = "0.8", default-features = false } -serde_ = { version = "1", package = "serde", default-features = false, features = [ +serde = { version = "1", default-features = false, features = [ "derive", ], optional = true } subtle = { version = "2.3", default-features = false } -voprf = { version = "=0.4.0-pre.3", default-features = false, features = [ - "danger", -] } +voprf = { version = "0.4.1", default-features = false, features = ["danger"] } zeroize = { version = "1.5", features = ["zeroize_derive"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -56,19 +47,28 @@ getrandom = { version = "0.2", features = ["js"], optional = true } [dev-dependencies] bincode = "1" -chacha20poly1305 = "=0.10.0-pre" -criterion = "0.4" +chacha20poly1305 = "0.10" +criterion = "0.5" hex = "0.4" json = "0.12" -p256 = { version = "0.11", default-features = false, features = [ +p256 = { version = "0.13", default-features = false, features = [ + "hash2curve", + "voprf", +] } +p384 = { version = "0.13", default-features = false, features = [ + "hash2curve", + "voprf", +] } +p521 = { version = "0.13.3", default-features = false, features = [ "hash2curve", "voprf", ] } proptest = "1" rand = "0.8" regex = "1" -rustyline = "9" -scrypt = "0.10" +# MSRV +rustyline = "14" +scrypt = "0.11" serde_json = "1" [[bench]] @@ -76,7 +76,8 @@ harness = false name = "opaque" [package.metadata.docs.rs] -features = ["argon2", "std", "x25519-u64"] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] targets = [] [[example]] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 09250ca8..00000000 --- a/LICENSE +++ /dev/null @@ -1,12 +0,0 @@ -## License - -Licensed under either of - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall -be dual licensed as above, without any additional terms or conditions. diff --git a/README.md b/README.md index dcfabbcd..aa92edbb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## The OPAQUE key exchange protocol ![Build Status](https://github.com/novifinancial/opaque-ke/workflows/Rust%20CI/badge.svg) +## The OPAQUE key exchange protocol ![Build Status](https://github.com/facebook/opaque-ke/workflows/Rust%20CI/badge.svg) [OPAQUE](https://eprint.iacr.org/2018/163.pdf) is an asymmetric 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. @@ -22,12 +22,12 @@ Installation Add the following line to the dependencies of your `Cargo.toml`: ``` -opaque-ke = "2" +opaque-ke = "2.1.0-pre.1" ``` ### Minimum Supported Rust Version -Rust **1.57** or higher. +Rust **1.74** or higher. Audit ----- @@ -42,7 +42,9 @@ Resources - [OPAQUE academic publication](https://eprint.iacr.org/2018/163.pdf), including formal definitions and a proof of security - [draft-irtf-cfrg-opaque-10](https://datatracker.ietf.org/doc/draft-irtf-cfrg-opaque/10/), 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 -- [opaque-wasm](https://github.com/marucjmar/opaque-wasm), a WebAssembly package for this library +- [@serenity-kit/opaque](https://github.com/serenity-kit/opaque), a WebAssembly package for this library +- [opaque-wasm](https://github.com/marucjmar/opaque-wasm), a WebAssembly package for this library. A comparison between `@serenity-kit/opaque` and `opaque-wasm` can be found [here](https://opaque-documentation.netlify.app/docs/faq#how-does-it-compare-to-opaque-wasm) +- [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 ------------ @@ -60,4 +62,6 @@ improvements to the library. License ------- -This project is [licensed](./LICENSE) under either Apache 2.0 or MIT, at your option. +This project is dual-licensed under either the [MIT license](./LICENSE-MIT) +or the [Apache License, Version 2.0](./LICENSE-APACHE). +You may select, at your option, one of the above-listed licenses. diff --git a/benches/opaque.rs b/benches/opaque.rs index 15fd4d49..47789e8e 100644 --- a/benches/opaque.rs +++ b/benches/opaque.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. #[macro_use] extern crate criterion; @@ -12,15 +13,9 @@ use criterion::Criterion; use opaque_ke::*; use rand::rngs::OsRng; -#[cfg(feature = "ristretto255-u64")] -static SUFFIX: &str = "ristretto255-u64"; -#[cfg(feature = "ristretto255-u32")] -static SUFFIX: &str = "ristretto255-u32"; -#[cfg(feature = "ristretto255-fiat-u64")] -static SUFFIX: &str = "ristretto255-fiat-u64"; -#[cfg(feature = "ristretto255-fiat-u32")] -static SUFFIX: &str = "ristretto255-fiat-u32"; -#[cfg(all(not(feature = "ristretto255")))] +#[cfg(feature = "ristretto255")] +static SUFFIX: &str = "ristretto255"; +#[cfg(not(feature = "ristretto255"))] static SUFFIX: &str = "p256"; struct Default; @@ -44,7 +39,7 @@ impl CipherSuite for Default { fn server_setup(c: &mut Criterion) { let mut rng = OsRng; - c.bench_function(&format!("server setup ({})", SUFFIX), move |b| { + c.bench_function(&format!("server setup ({SUFFIX})"), move |b| { b.iter(|| { ServerSetup::::new(&mut rng); }) @@ -55,14 +50,11 @@ fn client_registration_start(c: &mut Criterion) { let mut rng = OsRng; let password = b"password"; - c.bench_function( - &format!("client registration start ({})", SUFFIX), - move |b| { - b.iter(|| { - ClientRegistration::::start(&mut rng, password).unwrap(); - }) - }, - ); + c.bench_function(&format!("client registration start ({SUFFIX})"), move |b| { + b.iter(|| { + ClientRegistration::::start(&mut rng, password).unwrap(); + }) + }); } fn server_registration_start(c: &mut Criterion) { @@ -73,19 +65,16 @@ fn server_registration_start(c: &mut Criterion) { let client_registration_start_result = ClientRegistration::::start(&mut rng, password).unwrap(); - c.bench_function( - &format!("server registration start ({})", SUFFIX), - move |b| { - b.iter(|| { - ServerRegistration::::start( - &server_setup, - client_registration_start_result.message.clone(), - username, - ) - .unwrap(); - }) - }, - ); + c.bench_function(&format!("server registration start ({SUFFIX})"), move |b| { + b.iter(|| { + ServerRegistration::::start( + &server_setup, + client_registration_start_result.message.clone(), + username, + ) + .unwrap(); + }) + }); } fn client_registration_finish(c: &mut Criterion) { @@ -103,7 +92,7 @@ fn client_registration_finish(c: &mut Criterion) { .unwrap(); c.bench_function( - &format!("client registration finish ({})", SUFFIX), + &format!("client registration finish ({SUFFIX})"), move |b| { b.iter(|| { client_registration_start_result @@ -145,7 +134,7 @@ fn server_registration_finish(c: &mut Criterion) { .unwrap(); c.bench_function( - &format!("server registration finish ({})", SUFFIX), + &format!("server registration finish ({SUFFIX})"), move |b| { b.iter(|| { ServerRegistration::finish(client_registration_finish_result.clone().message); @@ -158,7 +147,7 @@ fn client_login_start(c: &mut Criterion) { let mut rng = OsRng; let password = b"password"; - c.bench_function(&format!("client login start ({})", SUFFIX), move |b| { + c.bench_function(&format!("client login start ({SUFFIX})"), move |b| { b.iter(|| { ClientLogin::::start(&mut rng, password).unwrap(); }) @@ -190,22 +179,19 @@ fn server_login_start_real(c: &mut Criterion) { let password_file = ServerRegistration::finish(client_registration_finish_result.message); let client_login_start_result = ClientLogin::::start(&mut rng, password).unwrap(); - c.bench_function( - &format!("server login start (real) ({})", SUFFIX), - move |b| { - b.iter(|| { - ServerLogin::start( - &mut rng, - &server_setup, - Some(password_file.clone()), - client_login_start_result.clone().message, - username, - ServerLoginStartParameters::default(), - ) - .unwrap(); - }) - }, - ); + c.bench_function(&format!("server login start (real) ({SUFFIX})"), move |b| { + b.iter(|| { + ServerLogin::start( + &mut rng, + &server_setup, + Some(password_file.clone()), + client_login_start_result.clone().message, + username, + ServerLoginStartParameters::default(), + ) + .unwrap(); + }) + }); } fn server_login_start_fake(c: &mut Criterion) { @@ -215,22 +201,19 @@ fn server_login_start_fake(c: &mut Criterion) { let server_setup = ServerSetup::::new(&mut rng); let client_login_start_result = ClientLogin::::start(&mut rng, password).unwrap(); - c.bench_function( - &format!("server login start (fake) ({})", SUFFIX), - move |b| { - b.iter(|| { - ServerLogin::start( - &mut rng, - &server_setup, - None, - client_login_start_result.clone().message, - username, - ServerLoginStartParameters::default(), - ) - .unwrap(); - }) - }, - ); + c.bench_function(&format!("server login start (fake) ({SUFFIX})"), move |b| { + b.iter(|| { + ServerLogin::start( + &mut rng, + &server_setup, + None, + client_login_start_result.clone().message, + username, + ServerLoginStartParameters::default(), + ) + .unwrap(); + }) + }); } fn client_login_finish(c: &mut Criterion) { @@ -267,7 +250,7 @@ fn client_login_finish(c: &mut Criterion) { ) .unwrap(); - c.bench_function(&format!("client login finish ({})", SUFFIX), move |b| { + c.bench_function(&format!("client login finish ({SUFFIX})"), move |b| { b.iter(|| { client_login_start_result .clone() @@ -324,7 +307,7 @@ fn server_login_finish(c: &mut Criterion) { ) .unwrap(); - c.bench_function(&format!("server login finish ({})", SUFFIX), move |b| { + c.bench_function(&format!("server login finish ({SUFFIX})"), move |b| { b.iter(|| { server_login_start_result .clone() diff --git a/examples/digital_locker.rs b/examples/digital_locker.rs index 6bb5d737..d595df3a 100644 --- a/examples/digital_locker.rs +++ b/examples/digital_locker.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Demonstrates an implementation of a server-side secured digital locker using //! the client's OPAQUE export key, over a command-line interface @@ -27,7 +28,7 @@ use std::process::exit; -use chacha20poly1305::aead::{Aead, NewAead}; +use chacha20poly1305::aead::{Aead, KeyInit}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use generic_array::GenericArray; use opaque_ke::ciphersuite::CipherSuite; @@ -40,6 +41,7 @@ use opaque_ke::{ ServerLoginStartParameters, ServerRegistration, ServerRegistrationLen, ServerSetup, }; use rustyline::error::ReadlineError; +use rustyline::history::DefaultHistory; use rustyline::Editor; // The ciphersuite trait allows to specify the underlying primitives that will @@ -216,7 +218,7 @@ fn main() { let mut rng = OsRng; let server_setup = ServerSetup::::new(&mut rng); - let mut rl = Editor::<()>::new(); + let mut rl = Editor::<(), _>::new().unwrap(); let mut registered_lockers: Vec = vec![]; loop { display_lockers(®istered_lockers); @@ -275,13 +277,10 @@ fn main() { ®istered_lockers[locker_index], ) { Ok(contents) => { - println!("\n\nSuccess! Contents: {}\n\n", contents); + println!("\n\nSuccess! Contents: {contents}\n\n"); } Err(err) => { - println!( - "\n\nError encountered, could not open locker: {}\n\n", - err - ); + println!("\n\nError encountered, could not open locker: {err}\n\n"); } } } @@ -304,10 +303,7 @@ fn display_lockers(lockers: &[Locker]) { locker_numbers.push(i); } - println!( - "\nCurrently registered locker numbers: {:?}\n", - locker_numbers - ); + println!("\nCurrently registered locker numbers: {locker_numbers:?}\n"); } // Handle readline errors @@ -320,7 +316,7 @@ fn handle_error(err: ReadlineError) { println!("CTRL-D"); } err => { - println!("Error: {:?}", err); + println!("Error: {err:?}"); } } } @@ -329,11 +325,11 @@ fn handle_error(err: ReadlineError) { fn get_two_strings( s1: &str, s2: &str, - rl: &mut Editor<()>, + rl: &mut Editor<(), DefaultHistory>, string1: Option, ) -> (String, String) { let query = if string1.is_none() { s1 } else { s2 }; - let readline = rl.readline(&format!("{}: ", query)); + let readline = rl.readline(&format!("{query}: ")); match readline { Ok(line) => match string1 { Some(x) => (x, line), diff --git a/examples/simple_login.rs b/examples/simple_login.rs index 39296bee..d6ed4676 100644 --- a/examples/simple_login.rs +++ b/examples/simple_login.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Demonstrates a simple client-server password-based login protocol using //! OPAQUE, over a command-line interface @@ -35,6 +36,7 @@ use opaque_ke::{ ServerLoginStartParameters, ServerRegistration, ServerRegistrationLen, ServerSetup, }; use rustyline::error::ReadlineError; +use rustyline::history::DefaultHistory; use rustyline::Editor; // The ciphersuite trait allows to specify the underlying primitives that will @@ -160,7 +162,7 @@ fn main() { let mut rng = OsRng; let server_setup = ServerSetup::::new(&mut rng); - let mut rl = Editor::<()>::new(); + let mut rl = Editor::<(), _>::new().unwrap(); let mut registered_users = HashMap::>>::new(); loop { @@ -228,7 +230,7 @@ fn handle_error(err: ReadlineError) { println!("CTRL-D"); } err => { - println!("Error: {:?}", err); + println!("Error: {err:?}"); } } } @@ -237,11 +239,11 @@ fn handle_error(err: ReadlineError) { fn get_two_strings( s1: &str, s2: &str, - rl: &mut Editor<()>, + rl: &mut Editor<(), DefaultHistory>, string1: Option, ) -> (String, String) { let query = if string1.is_none() { s1 } else { s2 }; - let readline = rl.readline(&format!("{}: ", query)); + let readline = rl.readline(&format!("{query}: ")); match readline { Ok(line) => match string1 { Some(x) => (x, line), diff --git a/scripts/digital_locker.exp b/scripts/digital_locker.exp index c36c8ac7..8e3cbb31 100644 --- a/scripts/digital_locker.exp +++ b/scripts/digital_locker.exp @@ -1,8 +1,11 @@ #!/bin/expect -f -# Copyright (c) Facebook, Inc. and its affiliates. + +# Copyright (c) Meta Platforms, Inc. and affiliates. # -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. +# 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. set timeout 1 spawn cargo run --example digital_locker diff --git a/scripts/simple_login.exp b/scripts/simple_login.exp index c112a628..0a5a0a20 100644 --- a/scripts/simple_login.exp +++ b/scripts/simple_login.exp @@ -1,11 +1,14 @@ #!/bin/expect -f -# Copyright (c) Facebook, Inc. and its affiliates. + +# Copyright (c) Meta Platforms, Inc. and affiliates. # -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. +# 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. set timeout 1 -spawn cargo run --example simple_login +spawn cargo run --example simple_login --features argon2 match_max 100000 sleep 1 expect "* diff --git a/src/ciphersuite.rs b/src/ciphersuite.rs index c6143793..1cfa92e9 100644 --- a/src/ciphersuite.rs +++ b/src/ciphersuite.rs @@ -1,11 +1,12 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. -//! Defines the CipherSuite trait to specify the underlying primitives for +//! Defines the [`CipherSuite`] trait to specify the underlying primitives for //! OPAQUE use digest::core_api::{BlockSizeUser, CoreProxy}; diff --git a/src/envelope.rs b/src/envelope.rs index b0b8510a..e7e3c9f7 100644 --- a/src/envelope.rs +++ b/src/envelope.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use core::convert::TryFrom; use core::ops::Add; @@ -35,11 +36,7 @@ const STR_PRIVATE_KEY: [u8; 10] = *b"PrivateKey"; const STR_OPAQUE_DERIVE_AUTH_KEY_PAIR: [u8; 24] = *b"OPAQUE-DeriveAuthKeyPair"; type NonceLen = U32; -#[cfg_attr( - feature = "serde", - derive(serde::Deserialize, serde::Serialize), - serde(crate = "serde") -)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)] pub(crate) enum InnerEnvelopeMode { Zero = 0, @@ -73,7 +70,7 @@ impl TryFrom for InnerEnvelopeMode { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)] pub(crate) struct Envelope @@ -346,7 +343,7 @@ where .map_err(|_| InternalError::HkdfError)?; let client_static_keypair = KeyPair::::from_private_key_slice( &CS::KeGroup::serialize_sk(CS::KeGroup::derive_auth_keypair::( - keypair_seed.as_slice(), + keypair_seed, &GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), )?), )?; @@ -372,7 +369,7 @@ where .map_err(|_| InternalError::HkdfError)?; let client_static_keypair = KeyPair::::from_private_key_slice( &CS::KeGroup::serialize_sk(CS::KeGroup::derive_auth_keypair::( - keypair_seed.as_slice(), + keypair_seed, &GenericArray::from(STR_OPAQUE_DERIVE_AUTH_KEY_PAIR), )?), )?; diff --git a/src/errors.rs b/src/errors.rs index 66aba7cb..d3867630 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! A list of error types which are produced during an execution of the protocol use core::convert::Infallible; @@ -20,6 +21,7 @@ pub enum InternalError { Custom(T), /// Deserializing from a byte sequence failed InvalidByteSequence, + #[allow(clippy::doc_markdown)] /// Invalid length for {name}: expected {len}, but is actually {actual_len}. SizeError { /// name @@ -87,7 +89,7 @@ impl Debug for InternalError { impl Error for InternalError {} impl InternalError { - /// Convert `InternalError` into `InternalError + /// Convert `InternalError` into `InternalError` pub fn into_custom(self) -> InternalError { match self { Self::Custom(_) => unreachable!(), @@ -184,7 +186,7 @@ impl From<::core::convert::Infallible> for ProtocolError { } impl ProtocolError { - /// Convert `ProtocolError` into `ProtocolError + /// Convert `ProtocolError` into `ProtocolError` pub fn into_custom(self) -> ProtocolError { match self { Self::LibraryError(internal_error) => { diff --git a/src/hash.rs b/src/hash.rs index f28e441e..2c51e77d 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,15 +1,16 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! A convenience trait for digest bounds used throughout the library use digest::block_buffer::Eager; use digest::core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore}; -use digest::{Digest, FixedOutputReset, HashMarker, OutputSizeUser}; +use digest::{FixedOutputReset, HashMarker, OutputSizeUser}; use generic_array::typenum::{IsLess, Le, NonZero, U256}; pub(crate) type OutputSize = <::Core as OutputSizeUser>::OutputSize; @@ -31,11 +32,12 @@ where { } -/// Trait inheriting the requirements from digest::Digest for compatibility with -/// HKDF and HMAC Associated types could be simplified when they are made as -/// defaults: +/// Trait inheriting the requirements from [`digest::Digest`] for compatibility +/// with HKDF and HMAC Associated types could be simplified when they are made +/// as defaults: pub trait Hash: - Digest + Default + + HashMarker + OutputSizeUser> + BlockSizeUser + FixedOutputReset @@ -49,7 +51,8 @@ where } impl< - T: Digest + T: Default + + HashMarker + OutputSizeUser> + BlockSizeUser + FixedOutputReset diff --git a/src/key_exchange/group/x25519.rs b/src/key_exchange/group/curve25519.rs similarity index 68% rename from src/key_exchange/group/x25519.rs rename to src/key_exchange/group/curve25519.rs index bf670677..c57154b4 100644 --- a/src/key_exchange/group/x25519.rs +++ b/src/key_exchange/group/curve25519.rs @@ -1,18 +1,18 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. -//! Key Exchange group implementation for X25519 +//! Key Exchange group implementation for Curve25519 -use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::Identity; use digest::core_api::BlockSizeUser; -use digest::Digest; +use digest::{FixedOutput, HashMarker}; use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64}; use generic_array::GenericArray; @@ -22,11 +22,11 @@ use subtle::ConstantTimeEq; use super::KeGroup; use crate::errors::InternalError; -/// Implementation for X25519. -pub struct X25519; +/// Implementation for Curve25519. +pub struct Curve25519; -/// The implementation of such a subgroup for Ristretto -impl KeGroup for X25519 { +/// The implementation of such a subgroup for Curve25519 +impl KeGroup for Curve25519 { type Pk = MontgomeryPoint; type PkLen = U32; type Sk = Scalar; @@ -47,9 +47,11 @@ impl KeGroup for X25519 { fn random_sk(rng: &mut R) -> Self::Sk { loop { - let scalar = Scalar::random(rng); + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + let scalar = Scalar::from_bytes_mod_order_wide(&scalar_bytes); - if scalar != Scalar::zero() { + if scalar != Scalar::ZERO { break scalar; } } @@ -59,17 +61,17 @@ impl KeGroup for X25519 { // fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { let mut uniform_bytes = GenericArray::<_, U64>::default(); - ExpandMsgXmd::::expand_message(input, dst, 64) + ExpandMsgXmd::::expand_message(input, &[dst], 64) .map_err(|_| InternalError::HashToScalar)? .fill_bytes(&mut uniform_bytes); let scalar = Scalar::from_bytes_mod_order_wide(&uniform_bytes.into()); - if scalar == Scalar::zero() { + if scalar == Scalar::ZERO { Err(InternalError::HashToScalar) } else { Ok(scalar) @@ -77,11 +79,11 @@ impl KeGroup for X25519 { } fn is_zero_scalar(scalar: Self::Sk) -> subtle::Choice { - scalar.ct_eq(&Scalar::zero()) + scalar.ct_eq(&Scalar::ZERO) } fn public_key(sk: Self::Sk) -> Self::Pk { - (&ED25519_BASEPOINT_TABLE * &sk).to_montgomery() + MontgomeryPoint::mul_base(&sk) } fn diffie_hellman(pk: Self::Pk, sk: Self::Sk) -> GenericArray { @@ -96,8 +98,8 @@ impl KeGroup for X25519 { bytes .try_into() .ok() - .and_then(Scalar::from_canonical_bytes) - .filter(|scalar| scalar != &Scalar::zero()) + .and_then(|bytes| Scalar::from_canonical_bytes(bytes).into()) + .filter(|scalar| scalar != &Scalar::ZERO) .ok_or(InternalError::PointError) } } diff --git a/src/key_exchange/group/elliptic_curve.rs b/src/key_exchange/group/elliptic_curve.rs index b1bf5771..b22d28ea 100644 --- a/src/key_exchange/group/elliptic_curve.rs +++ b/src/key_exchange/group/elliptic_curve.rs @@ -1,17 +1,18 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use digest::core_api::BlockSizeUser; -use digest::Digest; +use digest::{FixedOutput, HashMarker}; use elliptic_curve::group::cofactor::CofactorGroup; use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest}; use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}; use elliptic_curve::{ - AffinePoint, Field, FieldSize, Group, ProjectivePoint, PublicKey, Scalar, SecretKey, + AffinePoint, Field, FieldBytesSize, Group, ProjectivePoint, PublicKey, Scalar, SecretKey, }; use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::GenericArray; @@ -23,18 +24,18 @@ use crate::errors::InternalError; impl KeGroup for G where G: GroupDigest, - FieldSize: ModulusSize, + FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, ProjectivePoint: CofactorGroup + ToEncodedPoint, Scalar: FromOkm, { type Pk = ProjectivePoint; - type PkLen = as ModulusSize>::CompressedPointSize; + type PkLen = as ModulusSize>::CompressedPointSize; type Sk = Scalar; - type SkLen = FieldSize; + type SkLen = FieldBytesSize; fn serialize_pk(pk: Self::Pk) -> GenericArray { GenericArray::clone_from_slice(pk.to_encoded_point(true).as_bytes()) @@ -51,13 +52,13 @@ where } // Implements the `HashToScalar()` function from - // - fn hash_to_scalar(input: &[&[u8]], dst: &[u8]) -> Result + // + fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { - Self::hash_to_scalar::>(input, dst) + Self::hash_to_scalar::>(input, &[dst]) .map_err(|_| InternalError::HashToScalar) .and_then(|scalar| { if bool::from(scalar.is_zero()) { @@ -85,7 +86,7 @@ where } fn deserialize_sk(bytes: &[u8]) -> Result { - SecretKey::::from_be_bytes(bytes) + SecretKey::::from_slice(bytes) .map(|secret_key| *secret_key.to_nonzero_scalar()) .map_err(|_| InternalError::PointError) } diff --git a/src/key_exchange/group/mod.rs b/src/key_exchange/group/mod.rs index fe2dd283..e2582301 100644 --- a/src/key_exchange/group/mod.rs +++ b/src/key_exchange/group/mod.rs @@ -1,20 +1,21 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. -//! Includes the KeGroup trait and definitions for the key exchange groups +//! Includes the [`KeGroup`] trait and definitions for the key exchange groups +#[cfg(feature = "curve25519")] +pub mod curve25519; mod elliptic_curve; #[cfg(feature = "ristretto255")] pub mod ristretto255; -#[cfg(feature = "x25519")] -pub mod x25519; use digest::core_api::BlockSizeUser; -use digest::{Digest, OutputSizeUser}; +use digest::{FixedOutput, HashMarker, OutputSizeUser}; use generic_array::sequence::Concat; use generic_array::typenum::{IsLess, IsLessOrEqual, U11, U256}; use generic_array::{ArrayLength, GenericArray}; @@ -50,17 +51,18 @@ pub trait KeGroup { /// [`u16::MAX`]. fn hash_to_scalar(input: &[&[u8]], dst: &[u8]) -> Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual; - /// Corresponds to the DeriveAuthKeyPair() function defined in + /// Corresponds to the `DeriveAuthKeyPair()` function defined in /// /// /// Note that we cannot call the voprf crate directly since we need to - /// ensure that the KeGroup is used for the hash_to_scalar operation (as - /// opposed to the OprfGroup). + /// ensure that the [`KeGroup`] is used for the + /// [`hash_to_scalar`](Self::hash_to_scalar) operation (as opposed to + /// the [`OprfGroup`](voprf::Group)). fn derive_auth_keypair( - seed: &[u8], + seed: GenericArray, info: &[u8], ) -> Result where @@ -78,7 +80,7 @@ pub trait KeGroup { // skS = G.HashToScalar(deriveInput || I2OSP(counter, 1), DST = "DeriveKeyPair" // || contextString) let sk_s = Self::hash_to_scalar::( - &[seed, &info_len, info, &counter.to_be_bytes()], + &[&seed, &info_len, info, &counter.to_be_bytes()], &dst, ) .map_err(|_| InternalError::OprfError(voprf::Error::DeriveKeyPair))?; @@ -120,9 +122,19 @@ where ::OutputSize: IsLess + IsLessOrEqual<::BlockSize>, { + // FIXME: this should be in voprf library + let cs_id_u16: u16 = match CS::ID { + "ristretto255-SHA512" => 0x0001, + "decaf448-SHAKE256" => 0x0002, + "P256-SHA256" => 0x0003, + "P384-SHA384" => 0x0004, + "P521-SHA512" => 0x0005, + _ => panic!("Incompatible ciphersuite: {}", CS::ID), + }; + GenericArray::from(STR_VOPRF) .concat([mode.to_u8()].into()) - .concat(CS::ID.to_be_bytes().into()) + .concat(cs_id_u16.to_be_bytes().into()) } fn i2osp_2(input: usize) -> Result<[u8; 2], InternalError> { diff --git a/src/key_exchange/group/ristretto255.rs b/src/key_exchange/group/ristretto255.rs index e9665adf..710f9e28 100644 --- a/src/key_exchange/group/ristretto255.rs +++ b/src/key_exchange/group/ristretto255.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Key Exchange group implementation for ristretto255 @@ -12,7 +13,7 @@ use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::traits::Identity; use digest::core_api::BlockSizeUser; -use digest::Digest; +use digest::{FixedOutput, HashMarker}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32}; use generic_array::GenericArray; use rand::{CryptoRng, RngCore}; @@ -38,11 +39,8 @@ impl KeGroup for Ristretto255 { } fn deserialize_pk(bytes: &[u8]) -> Result { - if bytes.len() != 32 { - return Err(InternalError::PointError); - } - CompressedRistretto::from_slice(bytes) + .map_err(|_| InternalError::PointError)? .decompress() .filter(|point| point != &RistrettoPoint::identity()) .ok_or(InternalError::PointError) @@ -66,25 +64,25 @@ impl KeGroup for Ristretto255 { } }; - if scalar != Scalar::zero() { + if scalar != Scalar::ZERO { break scalar; } } } // Implements the `HashToScalar()` function from - // + // fn hash_to_scalar<'a, H>(input: &[&[u8]], dst: &[u8]) -> Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { - ::hash_to_scalar::(input, dst) + ::hash_to_scalar::(input, &[dst]) .map_err(InternalError::OprfInternalError) } fn is_zero_scalar(scalar: Self::Sk) -> subtle::Choice { - scalar.ct_eq(&Scalar::zero()) + scalar.ct_eq(&Scalar::ZERO) } fn public_key(sk: Self::Sk) -> Self::Pk { @@ -103,15 +101,15 @@ impl KeGroup for Ristretto255 { bytes .try_into() .ok() - .and_then(Scalar::from_canonical_bytes) - .filter(|scalar| scalar != &Scalar::zero()) + .and_then(|bytes| Scalar::from_canonical_bytes(bytes).into()) + .filter(|scalar| scalar != &Scalar::ZERO) .ok_or(InternalError::PointError) } } #[cfg(feature = "ristretto255-voprf")] impl voprf::CipherSuite for Ristretto255 { - const ID: u16 = voprf::Ristretto255::ID; + const ID: &'static str = voprf::Ristretto255::ID; type Group = ::Group; @@ -129,10 +127,10 @@ impl Group for Ristretto255 { fn hash_to_curve( input: &[&[u8]], - dst: &[u8], + dst: &[&[u8]], ) -> voprf::Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { ::hash_to_curve::(input, dst) @@ -140,10 +138,10 @@ impl Group for Ristretto255 { fn hash_to_scalar( input: &[&[u8]], - dst: &[u8], + dst: &[&[u8]], ) -> voprf::Result where - H: Digest + BlockSizeUser, + H: BlockSizeUser + Default + FixedOutput + HashMarker, H::OutputSize: IsLess + IsLessOrEqual, { ::hash_to_scalar::(input, dst) diff --git a/src/key_exchange/mod.rs b/src/key_exchange/mod.rs index a4cfd515..afbdb115 100644 --- a/src/key_exchange/mod.rs +++ b/src/key_exchange/mod.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Includes instantiations of key exchange protocols used in the login step for //! OPAQUE diff --git a/src/key_exchange/traits.rs b/src/key_exchange/traits.rs index 2cf95265..c31d0e9e 100644 --- a/src/key_exchange/traits.rs +++ b/src/key_exchange/traits.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use digest::core_api::BlockSizeUser; use digest::Output; diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 8e13485b..f57e4924 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! An implementation of the Triple Diffie-Hellman key exchange protocol use core::convert::TryFrom; @@ -54,7 +55,7 @@ pub struct TripleDh; #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Sk)] @@ -67,7 +68,7 @@ pub struct Ke1State { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)] @@ -80,7 +81,7 @@ pub struct Ke1Message { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)] pub struct Ke2State @@ -98,7 +99,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk)] @@ -117,7 +118,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, ZeroizeOnDrop)] pub struct Ke3Message @@ -207,7 +208,7 @@ where .chain_iter(id_s.into_iter()) .chain_iter(l2_bytes) .chain(server_nonce) - .chain(&server_e_kp.public().serialize()); + .chain(server_e_kp.public().serialize()); let result = derive_3dh_keys::( TripleDhComponents { diff --git a/src/keypair.rs b/src/keypair.rs index 332319d9..be751937 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Contains the keypair types that must be supplied for the OPAQUE API @@ -20,13 +21,10 @@ use crate::key_exchange::group::KeGroup; #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = "S: serde::Deserialize<'de>", - serialize = "S: serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = "S: serde::Deserialize<'de>", + serialize = "S: serde::Serialize" + )) )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; KG::Pk, S)] @@ -46,15 +44,18 @@ impl> KeyPair { &self.sk } - /// Obtains a KeyPair from a slice representing the private key + /// Obtains a [`KeyPair`] from a slice representing the private key pub fn from_private_key_slice(input: &[u8]) -> Result> { Self::from_private_key(S::deserialize(input)?) } - /// Obtains a KeyPair from a private key - pub fn from_private_key(sk: S) -> Result> { - let pk = sk.public_key()?; - Ok(Self { pk, sk }) + /// Obtains a [`KeyPair`] from a private key + pub fn from_private_key(private_key: S) -> Result> { + let pk = private_key.public_key()?; + Ok(Self { + pk, + sk: private_key, + }) } } @@ -77,7 +78,7 @@ where KG::Sk: std::fmt::Debug, { /// Test-only strategy returning a proptest Strategy based on - /// generate_random + /// [`Self::generate_random`] fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy { use proptest::prelude::*; use rand::rngs::StdRng; @@ -231,6 +232,8 @@ mod tests { #[cfg(feature = "ristretto255")] inner::(); inner::<::p256::NistP256>(); + inner::<::p384::NistP384>(); + inner::<::p521::NistP521>(); } macro_rules! test { @@ -277,6 +280,8 @@ mod tests { #[cfg(feature = "ristretto255")] test!(ristretto, crate::Ristretto255); test!(p256, ::p256::NistP256); + test!(p384, ::p384::NistP384); + test!(p521, ::p521::NistP521); #[test] fn remote_key() { diff --git a/src/ksf.rs b/src/ksf.rs index 4af24151..b14e4305 100644 --- a/src/ksf.rs +++ b/src/ksf.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Trait specifying a key stretching function @@ -11,10 +12,6 @@ use generic_array::{ArrayLength, GenericArray}; use crate::errors::InternalError; -/// Recommended salt length for argon2-based password hashing. -#[cfg(feature = "argon2")] -const ARGON2_RECOMMENDED_SALT_LEN: usize = 16; - /// Used for the key stretching function in OPAQUE pub trait Ksf: Default { /// Computes the key stretching function @@ -44,7 +41,7 @@ impl Ksf for argon2::Argon2<'_> { input: GenericArray, ) -> Result, InternalError> { let mut output = GenericArray::default(); - self.hash_password_into(&input, &[0; ARGON2_RECOMMENDED_SALT_LEN], &mut output) + self.hash_password_into(&input, &[0; argon2::RECOMMENDED_SALT_LEN], &mut output) .map_err(|_| InternalError::KsfError)?; Ok(output) } diff --git a/src/lib.rs b/src/lib.rs index f929dc32..34050da9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! An implementation of the OPAQUE asymmetric password authentication key //! exchange protocol @@ -14,7 +15,7 @@ //! //! ### Minimum Supported Rust Version //! -//! Rust **1.57** or higher. +//! Rust **1.74** or higher. //! //! # Overview //! @@ -39,7 +40,7 @@ //! type Ksf = opaque_ke::ksf::Identity; //! } //! ``` -//! See [examples/simple_login.rs](https://github.com/novifinancial/opaque-ke/blob/main/examples/simple_login.rs) +//! See [examples/simple_login.rs](https://github.com/facebook/opaque-ke/blob/main/examples/simple_login.rs) //! for a working example of a simple password-based login using OPAQUE. //! //! Note that our choice of key stretching function in this example, `Identity`, @@ -76,34 +77,35 @@ //! let server_setup = ServerSetup::::new(&mut rng); //! # Ok::<(), ProtocolError>(()) //! ``` -//! The server must persist an instance of [ServerSetup] for the registration -//! and login steps. +//! The server must persist an instance of [`ServerSetup`] for the registration +//! and login steps, and can use [`ServerSetup::serialize`] and +//! [`ServerSetup::deserialize`] to save and restore the instance. //! //! ## Registration //! The registration protocol between the client and server consists of four -//! steps along with three messages: [RegistrationRequest], -//! [RegistrationResponse], and [RegistrationUpload]. A successful execution of -//! the registration protocol results in the server producing a password file +//! steps along with three messages: [`RegistrationRequest`], +//! [`RegistrationResponse`], and [`RegistrationUpload`]. A successful execution +//! of the registration protocol results in the server producing a password file //! corresponding to a server-side identifier for the client, along with the //! password provided by the client. This password file is typically stored in a //! key-value database, where the keys consist of these server-side identifiers //! for each client, and the values consist of their corresponding password //! files, to be retrieved upon future login attempts made by the client. //! It is your responsibility to ensure that the identifier used to form the -//! initial [RegistrationRequest], typically supplied by the client, matches -//! the database key used in the final [RegistrationUpload] step. +//! initial [`RegistrationRequest`], typically supplied by the client, matches +//! the database key used in the final [`RegistrationUpload`] step. //! -//! Note that the [RegistrationUpload] message contains sensitive information +//! Note that the [`RegistrationUpload`] message contains sensitive information //! (about as sensitive as a hash of the password), and hence should be //! protected with confidentiality guarantees by the consumer of this library. //! //! ### Client Registration Start //! In the first step of registration, the client chooses as input a -//! registration password. The client runs [ClientRegistration::start] to -//! produce a [ClientRegistrationStartResult], which consists of a -//! [RegistrationRequest] to be sent to the server and a [ClientRegistration] -//! which must be persisted on the client for the final step of client -//! registration. +//! registration password. The client runs [`ClientRegistration::start`] to +//! produce a [`ClientRegistrationStartResult`], which consists of a +//! [`RegistrationRequest`] to be sent to the server and a +//! [`ClientRegistration`] which must be persisted on the client for the final +//! step of client registration. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -137,10 +139,11 @@ //! //! ### Server Registration Start //! In the second step of registration, the server takes as input a persisted -//! instance of [ServerSetup], a [RegistrationRequest] from the client, and a -//! server-side identifier for the client. The server runs -//! [ServerRegistration::start] to produce a [ServerRegistrationStartResult], -//! which consists of a [RegistrationResponse] to be returned to the client. +//! instance of [`ServerSetup`], a [`RegistrationRequest`] from the client, and +//! a server-side identifier for the client. The server runs +//! [`ServerRegistration::start`] to produce a +//! [`ServerRegistrationStartResult`], which consists of a +//! [`RegistrationResponse`] to be returned to the client. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -183,10 +186,11 @@ //! //! ### Client Registration Finish //! In the third step of registration, the client takes as input a -//! [RegistrationResponse] from the server, and a [ClientRegistration] from the -//! first step of registration. The client runs [ClientRegistration::finish] to -//! produce a [ClientRegistrationFinishResult], which consists of a -//! [RegistrationUpload] to be sent to the server and an `export_key` field +//! [`RegistrationResponse`] from the server, and a [`ClientRegistration`] from +//! the first step of registration. The client runs +//! [`ClientRegistration::finish`] to +//! produce a [`ClientRegistrationFinishResult`], which consists of a +//! [`RegistrationUpload`] to be sent to the server and an `export_key` field //! which can be used optionally as described in the [Export Key](#export-key) //! section. //! ``` @@ -231,11 +235,11 @@ //! //! ### Server Registration Finish //! In the fourth step of registration, the server takes as input a -//! [RegistrationUpload] from the client, and a [ServerRegistration] from the -//! second step. The server runs [ServerRegistration::finish] to produce a -//! finalized [ServerRegistration]. At this point, the client can be considered -//! as successfully registered, and the server can invoke -//! [ServerRegistration::serialize] to store the password file for use during +//! [`RegistrationUpload`] from the client, and a [`ServerRegistration`] from +//! the second step. The server runs [`ServerRegistration::finish`] to produce a +//! finalized [`ServerRegistration`]. At this point, the client can be +//! considered as successfully registered, and the server can invoke +//! [`ServerRegistration::serialize`] to store the password file for use during //! the login protocol. //! ``` //! # use opaque_ke::{ @@ -277,8 +281,8 @@ //! //! ## Login //! The login protocol between a client and server also consists of four steps -//! along with three messages: [CredentialRequest], [CredentialResponse], -//! [CredentialFinalization]. The server is expected to have access to the +//! along with three messages: [`CredentialRequest`], [`CredentialResponse`], +//! [`CredentialFinalization`]. The server is expected to have access to the //! password file corresponding to an output of the registration phase (see //! [Dummy Server Login](#dummy-server-login) for handling the scenario where no //! password file is available). The login protocol will execute successfully @@ -287,9 +291,9 @@ //! //! ### Client Login Start //! In the first step of login, the client chooses as input a login password. -//! The client runs [ClientLogin::start] to produce an output consisting of a -//! [CredentialRequest] to be sent to the server, and a [ClientLogin] which must -//! be persisted on the client for the final step of client login. +//! The client runs [`ClientLogin::start`] to produce an output consisting of a +//! [`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::{ //! # errors::ProtocolError, @@ -321,12 +325,12 @@ //! //! ### Server Login Start //! In the second step of login, the server takes as input a persisted instance -//! of [ServerSetup], the password file output from registration, a -//! [CredentialRequest] from the client, and a server-side identifier for the -//! client. The server runs [ServerLogin::start] to produce an output consisting -//! of a [CredentialResponse] which is returned to the client, and a -//! [ServerLogin] which must be persisted on the server for the final step of -//! login. +//! of [`ServerSetup`], the password file output from registration, a +//! [`CredentialRequest`] from the client, and a server-side identifier for the +//! client. The server runs [`ServerLogin::start`] to produce an output +//! consisting of a [`CredentialResponse`] which is returned to the client, and +//! a [`ServerLogin`] which must be persisted on the server for the final step +//! of login. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -379,17 +383,25 @@ //! ``` //! Note that if there is no corresponding password file found for the user, the //! server can use `None` in place of `Some(password_file)` in order to generate -//! a [CredentialResponse] that is indistinguishable from a valid -//! [CredentialResponse] returned for a registered client. This allows the +//! a [`CredentialResponse`] that is indistinguishable from a valid +//! [`CredentialResponse`] returned for a registered client. This allows the //! server to prevent leaking information about whether or not a client has //! previously registered with the server. //! //! ### Client Login Finish -//! In the third step of login, the client takes as input a [CredentialResponse] -//! from the server. The client runs [ClientLogin::finish] and produces an -//! output consisting of a [CredentialFinalization] to be sent to the server to -//! complete the protocol, the `session_key` sequence of bytes which will match -//! the server's session key upon a successful login. +//! In the third step of login, the client takes as input a +//! [`CredentialResponse`] from the server and runs [`ClientLogin::finish`] +//! on it. +//! If the authentication is successful, then the client obtains a +//! [`ClientLoginFinishResult`]. Otherwise, on failure, the +//! algorithm outputs an +//! [`InvalidLoginError`](errors::ProtocolError::InvalidLoginError) error. +//! +//! The resulting [`ClientLoginFinishResult`] obtained by client in this step +//! contains, among other things, a [`CredentialFinalization`] to be sent to the +//! server to complete the protocol, and a +//! [`session_key`](struct.ClientLoginFinishResult.html#structfield.session_key) +//! which will match the server's session key upon a successful login. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -443,8 +455,8 @@ //! //! ### Server Login Finish //! In the fourth step of login, the server takes as input a -//! [CredentialFinalization] from the client and runs [ServerLogin::finish] to -//! produce an output consisting of the `session_key` sequence of bytes which +//! [`CredentialFinalization`] from the client and runs [`ServerLogin::finish`] +//! 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::{ @@ -508,8 +520,8 @@ //! `server_login_finish_result.session_key` which is guaranteed to match //! `client_login_finish_result.session_key` (see the [Session //! Key](#session-key) section). Otherwise, on failure, the -//! [ServerLogin::finish] algorithm outputs the error -//! [InvalidLoginError](errors::ProtocolError::InvalidLoginError). +//! [`ServerLogin::finish`] algorithm outputs the error +//! [`InvalidLoginError`](errors::ProtocolError::InvalidLoginError). //! //! # Advanced Usage //! @@ -522,26 +534,27 @@ //! //! Upon a successful completion of the OPAQUE protocol (the client runs login //! with the same password used during registration), the client and server have -//! access to a session key, which is a pseudorandomly distributed 32-byte -//! string which only the client and server know. Multiple login runs using the +//! access to a session key, which is a pseudorandomly distributed byte +//! string (of length equal to the output size of [`voprf::CipherSuite::Hash`]) +//! which only the client and server know. Multiple login runs using the //! same password for the same client will produce different session keys, //! distributed as uniformly random strings. Thus, the session key can be used //! to establish a secure channel between the client and server. //! //! The session key can be accessed from the `session_key` field of -//! [ClientLoginFinishResult] and [ServerLoginFinishResult]. See the combination -//! of [Client Login Finish](#client-login-finish) and [Server Login +//! [`ClientLoginFinishResult`] and [`ServerLoginFinishResult`]. See the +//! combination of [Client Login Finish](#client-login-finish) and [Server Login //! Finish](#server-login-finish) for example usage. //! //! ## Checking Server Consistency //! -//! A [ClientLoginFinishResult] contains the `server_s_pk` field, which is +//! A [`ClientLoginFinishResult`] contains the `server_s_pk` field, which is //! represents the static public key of the server that is established during //! the setup phase. This can be used by the client to verify the authenticity //! of the server it engages with during the login phase. In particular, the //! client can check that the static public key of the server supplied during //! registration (with the `server_s_pk` field of -//! [ClientRegistrationFinishResult]) matches this field during login. +//! [`ClientRegistrationFinishResult`]) matches this field during login. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -619,11 +632,12 @@ //! //! ## Export Key //! -//! The export key is a pseudorandomly distributed 32-byte string output by both -//! the [Client Registration Finish](#client-registration-finish) and [Client -//! Login Finish](#client-login-finish) steps. The same export key string will -//! be output by both functions only if the exact same password is passed to -//! [ClientRegistration::start] and [ClientLogin::start]. +//! The export key is a pseudorandomly distributed byte string +//! (of length equal to the output size of [`voprf::CipherSuite::Hash`]) output +//! by both the [Client Registration Finish](#client-registration-finish) and +//! [Client Login Finish](#client-login-finish) steps. The same export key +//! string will be output by both functions only if the exact same password is +//! passed to [`ClientRegistration::start`] and [`ClientLogin::start`]. //! //! The export key retains as much secrecy as the password itself, and is //! similarly derived through an evaluation of the key stretching function. @@ -634,11 +648,11 @@ //! which only the client should be able to process. For instance, if the server //! is expected to maintain any client-side secrets which require a password to //! access, then this export key can be used to encrypt these secrets so that -//! they remain hidden from the server (see [examples/digital_locker.rs](https://github.com/novifinancial/opaque-ke/blob/main/examples/digital_locker.rs) +//! they remain hidden from the server (see [examples/digital_locker.rs](https://github.com/facebook/opaque-ke/blob/main/examples/digital_locker.rs) //! for a working example). //! //! You can access the export key from the `export_key` field of -//! [ClientRegistrationFinishResult] and [ClientLoginFinishResult]. +//! [`ClientRegistrationFinishResult`] and [`ClientLoginFinishResult`]. //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -718,7 +732,7 @@ //! But, for applications that wish to cryptographically bind these identities //! to the registered password file as well as the session key output by the //! login phase, these custom identifiers can be specified through -//! [ClientRegistrationFinishParameters] in [Client Registration +//! [`ClientRegistrationFinishParameters`] in [Client Registration //! Finish](#client-registration-finish): //! ``` //! # use opaque_ke::{ @@ -767,7 +781,7 @@ //! ``` //! //! The same identifiers must also be supplied using -//! [ServerLoginStartParameters] in [Server Login Start](#server-login-start): +//! [`ServerLoginStartParameters`] in [Server Login Start](#server-login-start): //! ``` //! # use opaque_ke::{ //! # errors::ProtocolError, @@ -825,7 +839,7 @@ //! # Ok::<(), ProtocolError>(()) //! ``` //! -//! as well as [ClientLoginFinishParameters] in [Client Login +//! as well as [`ClientLoginFinishParameters`] in [Client Login //! Finish](#client-login-finish): //! ``` //! # use opaque_ke::{ @@ -899,9 +913,9 @@ //! configuration parameters to the security of the key exchange. During the //! login phase, the client and server can specify this context using: //! - The second login message, where the server can populate -//! [ServerLoginStartParameters], and +//! [`ServerLoginStartParameters`], and //! - The third login message, where the client can populate -//! [ClientLoginFinishParameters]. +//! [`ClientLoginFinishParameters`]. //! //! For both of these messages, the `WithContextAndIdentifiers` variant can be //! used to specify these fields in addition to [custom @@ -916,8 +930,8 @@ //! a "dummy" credential response message to the client for an unregistered //! client, which is indistinguishable from the normal credential response //! message that the server would return for a registered client. The dummy -//! message is created by passing a `None` to the password_file parameter for -//! [ServerLogin::start]. +//! message is created by passing a `None` to the `password_file` parameter for +//! [`ServerLogin::start`]. //! //! ## Remote Private Keys //! @@ -1089,7 +1103,7 @@ //! and implements the `Ksf` trait for `Argon2` with a set of default parameters. //! In general, secure instantiations should choose to invoke a memory-hard password //! hashing function when the client's password is expected to have low entropy, -//! instead of relying on [ksf::Identity] as done in the above example. The +//! instead of relying on [`ksf::Identity`] as done in the above example. The //! more computationally intensive the `Ksf` function is, the more resistant //! the server's password file records will be against offline dictionary and precomputation //! attacks; see [the OPAQUE paper](https://eprint.iacr.org/2018/163.pdf) for @@ -1097,23 +1111,12 @@ //! //! - The `serde` feature, enabled by default, provides convenience functions for serializing and deserializing with [serde](https://serde.rs/). //! -//! - The backend features are re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) -//! and allow for selecting the corresponding backend for the curve arithmetic -//! used. The `ristretto255-u64` feature is included as the default. Other -//! features are mapped as `ristretto255-u32`, `ristretto255-fiat-u64` and -//! `ristretto255-fiat-u32`. Any `ristretto255-*` backend feature will enable -//! the `ristretto255` feature, which can be used too, but keep in mind that -//! `curve25519-dalek` will fail to compile without a selected backend. This -//! enables the use of [`Ristretto255`] as a `KeGroup` and `OprfCs`. +//! - The `ristretto255` feature enables using [`Ristretto255`] as a `KeGroup` +//! and `OprfCs`. To select a specific backend see the [curve25519-dalek] +//! documentation. //! -//! - The `x25519` feature is similar to the `ristretto255` feature and requires -//! to select a backend like `x25519-u64`, other backends are the same as in -//! `ristretto255-*`. This enables [`X25519`] as a `KeGroup`. -//! -//! - The `ristretto255-simd` feature is re-exported from [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) -//! and enables parallel formulas, using either AVX2 or AVX512-IFMA. This will -//! automatically enable the `ristretto255-u64` feature and requires Rust -//! nightly. +//! - The `curve25519` feature enables Curve25519 as a `KeGroup`. To select a +//! specific backend see the [curve25519-dalek] documentation. //! //! - The `p256` feature enables the use of [`p256::NistP256`] as a `KeGroup` //! and a `OprfCs` for `CipherSuite`. @@ -1121,20 +1124,20 @@ //! - The `bench` feature is used only for running performance benchmarks for //! this implementation. //! +//! [curve25519-dalek]: +//! (https://docs.rs/curve25519-dalek/4.0.0-pre.5/curve25519_dalek/index.html#backends) //! [`p256::NistP256`]: https://docs.rs/p256/latest/p256/struct.NistP256.html -#![cfg_attr(not(test), deny(unsafe_code))] #![no_std] -#![warn(clippy::cargo, missing_docs)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(test), deny(unsafe_code))] +#![warn(clippy::cargo, clippy::doc_markdown, missing_docs, rustdoc::all)] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![allow(type_alias_bounds)] #[cfg(any(feature = "std", test))] extern crate std; -#[cfg(feature = "serde")] -extern crate serde_ as serde; - // Error types pub mod errors; @@ -1157,10 +1160,10 @@ mod tests; pub use ciphersuite::CipherSuite; pub use rand; +#[cfg(feature = "curve25519")] +pub use crate::key_exchange::group::curve25519::Curve25519; #[cfg(feature = "ristretto255")] pub use crate::key_exchange::group::ristretto255::Ristretto255; -#[cfg(feature = "x25519")] -pub use crate::key_exchange::group::x25519::X25519; pub use crate::messages::{ CredentialFinalization, CredentialFinalizationLen, CredentialRequest, CredentialRequestLen, CredentialResponse, CredentialResponseLen, RegistrationRequest, RegistrationRequestLen, diff --git a/src/messages.rs b/src/messages.rs index c1fa4e9c..ab9eb47f 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Contains the messages used for OPAQUE @@ -41,7 +42,7 @@ use crate::opaque::{MaskedResponse, MaskedResponseLen, ServerSetup}; #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::BlindedElement)] @@ -63,7 +64,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, ::Pk)] @@ -87,7 +88,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk)] @@ -113,15 +114,12 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = ", \ - CS::KeGroup>>::KE1Message: serde::Deserialize<'de>", - serialize = ", CS::KeGroup>>::KE1Message: \ - serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = ", CS::KeGroup>>::KE1Message: \ + serde::Deserialize<'de>", + serialize = ", CS::KeGroup>>::KE1Message: \ + serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( @@ -147,15 +145,12 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = ", \ - CS::KeGroup>>::KE2Message: serde::Deserialize<'de>", - serialize = ", CS::KeGroup>>::KE2Message: \ - serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = ", CS::KeGroup>>::KE2Message: \ + serde::Deserialize<'de>", + serialize = ", CS::KeGroup>>::KE2Message: \ + serde::Serialize" + )) )] #[derive_where(Clone)] #[derive_where( @@ -184,15 +179,12 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = ", \ - CS::KeGroup>>::KE3Message: serde::Deserialize<'de>", - serialize = ", CS::KeGroup>>::KE3Message: \ - serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = ", CS::KeGroup>>::KE3Message: \ + serde::Deserialize<'de>", + serialize = ", CS::KeGroup>>::KE3Message: \ + serde::Serialize" + )) )] #[derive_where(Clone)] #[derive_where( diff --git a/src/opaque.rs b/src/opaque.rs index c858b509..d7ff7016 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Provides the main OPAQUE API @@ -58,13 +59,10 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair"; #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = "S: serde::Deserialize<'de>", - serialize = "S: serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = "S: serde::Deserialize<'de>", + serialize = "S: serde::Serialize" + )) )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk, ::Sk, S)] @@ -88,7 +86,7 @@ pub struct ServerSetup< #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( @@ -113,7 +111,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; ::Pk)] @@ -130,18 +128,14 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = ", \ - CS::KeGroup>>::KE1Message: serde::Deserialize<'de>, , CS::KeGroup>>::KE1State: \ - serde::Deserialize<'de>", - serialize = ", CS::KeGroup>>::KE1Message: \ - serde::Serialize, , \ - CS::KeGroup>>::KE1State: serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = ", CS::KeGroup>>::KE1Message: \ + serde::Deserialize<'de>, , \ + CS::KeGroup>>::KE1State: serde::Deserialize<'de>", + serialize = ", CS::KeGroup>>::KE1Message: \ + serde::Serialize, , \ + CS::KeGroup>>::KE1State: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( @@ -168,15 +162,12 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde( - bound( - deserialize = ", CS::KeGroup>>::KE2State: \ - serde::Deserialize<'de>", - serialize = ", CS::KeGroup>>::KE2State: \ - serde::Serialize" - ), - crate = "serde" - ) + serde(bound( + deserialize = ", CS::KeGroup>>::KE2State: \ + serde::Deserialize<'de>", + serialize = ", CS::KeGroup>>::KE2State: \ + serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where( @@ -233,6 +224,10 @@ where Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Create [`ServerSetup`] with the given keypair + /// + /// 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( rng: &mut R, keypair: KeyPair, @@ -333,7 +328,7 @@ where } /// Returns an initial "blinded" request to send to the server, as well as a - /// ClientRegistration + /// [`ClientRegistration`] pub fn start( blinding_factor_rng: &mut R, password: &[u8], @@ -443,7 +438,7 @@ where } /// From the client's "blinded" password, returns a response to be sent back - /// to the client, as well as a ServerRegistration + /// to the client, as well as a [`ServerRegistration`] pub fn start>( server_setup: &ServerSetup, message: RegistrationRequest, @@ -453,7 +448,7 @@ where oprf_key_from_seed::(&server_setup.oprf_seed, credential_identifier)?; let server = voprf::OprfServer::new_with_key(&oprf_key)?; - let evaluation_element = server.evaluate(&message.blinded_element); + let evaluation_element = server.blind_evaluate(&message.blinded_element); Ok(ServerRegistrationStartResult { message: RegistrationResponse { @@ -466,7 +461,7 @@ where } /// From the client's cryptographic identifiers, fully populates and returns - /// a ServerRegistration + /// a [`ServerRegistration`] pub fn finish(message: RegistrationUpload) -> Self { Self(message) } @@ -545,7 +540,7 @@ where Le<< as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>: NonZero, { /// Returns an initial "blinded" password request to send to the server, as - /// well as a ClientLogin + /// well as a [`ClientLogin`] pub fn start( rng: &mut R, password: &[u8], @@ -696,7 +691,7 @@ where } /// From the client's "blinded" password, returns a challenge to be sent - /// back to the client, as well as a ServerLogin + /// back to the client, as well as a [`ServerLogin`] pub fn start>( rng: &mut R, server_setup: &ServerSetup, @@ -721,13 +716,7 @@ where }; let client_s_pk = record.0.client_s_pk.clone(); - - let context = if let Some(context) = context { - context - } else { - &[] - }; - + let context = context.unwrap_or(&[]); let server_s_sk = server_setup.keypair.private(); let server_s_pk = server_s_sk.public_key()?; @@ -760,7 +749,7 @@ where .map_err(ProtocolError::into_custom)?; let server = voprf::OprfServer::new_with_key(&oprf_key) .map_err(|e| ProtocolError::into_custom(e.into()))?; - let evaluation_element = server.evaluate(&credential_request.blinded_element); + let evaluation_element = server.blind_evaluate(&credential_request.blinded_element); let beta = OprfGroup::::serialize_elem(evaluation_element.value()); let credential_response_component = @@ -1150,7 +1139,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "", crate = "serde") + serde(bound = "") )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, PartialEq)] diff --git a/src/serialization/mod.rs b/src/serialization/mod.rs index a5305087..dd2a06ea 100644 --- a/src/serialization/mod.rs +++ b/src/serialization/mod.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use core::marker::PhantomData; @@ -12,7 +13,7 @@ use generic_array::typenum::{U0, U2}; use generic_array::{ArrayLength, GenericArray}; use hmac::Mac; -use crate::errors::{InternalError, ProtocolError}; +use crate::errors::ProtocolError; // Corresponds to the I2OSP() function from RFC8017 pub(crate) fn i2osp>( @@ -153,20 +154,6 @@ impl MacExt for T { } } -pub(crate) trait GenericArrayExt { - fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError>; -} - -impl> GenericArrayExt for GenericArray { - fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError> { - if slice.len() == L::USIZE { - Ok(Self::from_slice(slice)) - } else { - Err(InternalError::InvalidByteSequence) - } - } -} - #[cfg(test)] mod tests; diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs index 39b697e0..c8ffff95 100644 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use core::ops::Add; use std::vec; @@ -54,6 +55,24 @@ impl CipherSuite for P256 { type Ksf = crate::ksf::Identity; } +struct P384; + +impl CipherSuite for P384 { + type OprfCs = ::p384::NistP384; + type KeGroup = ::p384::NistP384; + type KeyExchange = TripleDh; + type Ksf = crate::ksf::Identity; +} + +struct P521; + +impl CipherSuite for P521 { + type OprfCs = ::p521::NistP521; + type KeGroup = ::p521::NistP521; + type KeyExchange = TripleDh; + type Ksf = crate::ksf::Identity; +} + fn random_point() -> ::Pk where as OutputSizeUser>::OutputSize: @@ -104,6 +123,8 @@ fn client_registration_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -157,6 +178,8 @@ fn server_registration_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -199,6 +222,8 @@ fn registration_request_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -250,6 +275,8 @@ fn registration_response_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -311,6 +338,8 @@ fn registration_upload_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -368,6 +397,8 @@ fn credential_request_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -456,6 +487,8 @@ fn credential_response_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -487,6 +520,8 @@ fn credential_finalization_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -554,6 +589,8 @@ fn client_login_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -593,6 +630,8 @@ fn ke1_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -636,6 +675,8 @@ fn ke2_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -670,6 +711,8 @@ fn ke3_message_roundtrip() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; + inner::()?; + inner::()?; Ok(()) } @@ -705,52 +748,52 @@ macro_rules! test { proptest! { #[test] fn test_nocrash_registration_request(bytes in vec(any::(), 0..200)) { - RegistrationRequest::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = RegistrationRequest::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_registration_response(bytes in vec(any::(), 0..200)) { - RegistrationResponse::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = RegistrationResponse::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_registration_upload(bytes in vec(any::(), 0..200)) { - RegistrationUpload::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = RegistrationUpload::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_credential_request(bytes in vec(any::(), 0..500)) { - CredentialRequest::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = CredentialRequest::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_credential_response(bytes in vec(any::(), 0..500)) { - CredentialResponse::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = CredentialResponse::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_credential_finalization(bytes in vec(any::(), 0..500)) { - CredentialFinalization::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = CredentialFinalization::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_client_registration(bytes in vec(any::(), 0..700)) { - ClientRegistration::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = ClientRegistration::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_server_registration(bytes in vec(any::(), 0..700)) { - ServerRegistration::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = ServerRegistration::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_client_login(bytes in vec(any::(), 0..700)) { - ClientLogin::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = ClientLogin::<$CS>::deserialize(&bytes).map_or(true, |_| true); } #[test] fn test_nocrash_server_login(bytes in vec(any::(), 0..700)) { - ServerLogin::<$CS>::deserialize(&bytes).map_or(true, |_| true); + let _ = ServerLogin::<$CS>::deserialize(&bytes).map_or(true, |_| true); } } } @@ -760,3 +803,5 @@ macro_rules! test { #[cfg(feature = "ristretto255")] test!(ristretto255, Ristretto255); test!(p256, P256); +test!(p384, P384); +test!(p521, P521); diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs index 24c55781..618c38a4 100644 --- a/src/tests/full_test.rs +++ b/src/tests/full_test.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. #![allow(unsafe_code)] @@ -61,24 +62,24 @@ impl CipherSuite for P256 { type Ksf = Identity; } -#[cfg(all(feature = "x25519", feature = "ristretto255"))] -struct X25519Ristretto255; +#[cfg(all(feature = "curve25519", feature = "ristretto255"))] +struct Curve25519Ristretto255; -#[cfg(all(feature = "x25519", feature = "ristretto255"))] -impl CipherSuite for X25519Ristretto255 { +#[cfg(all(feature = "curve25519", feature = "ristretto255"))] +impl CipherSuite for Curve25519Ristretto255 { type OprfCs = crate::Ristretto255; - type KeGroup = crate::X25519; + type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } -#[cfg(feature = "x25519")] -struct X25519P256; +#[cfg(feature = "curve25519")] +struct Curve25519P256; -#[cfg(feature = "x25519")] -impl CipherSuite for X25519P256 { +#[cfg(feature = "curve25519")] +impl CipherSuite for Curve25519P256 { type OprfCs = p256::NistP256; - type KeGroup = crate::X25519; + type KeGroup = crate::Curve25519; type KeyExchange = TripleDh; type Ksf = Identity; } @@ -122,7 +123,7 @@ static STR_PASSWORD: &str = "password"; static STR_CREDENTIAL_IDENTIFIER: &str = "credential_identifier"; // To regenerate these test vectors, run: -// cargo test --features x25519-u64 -- --nocapture generate_test_vectors +// cargo test --features curve25519-u64 -- --nocapture generate_test_vectors #[cfg(feature = "ristretto255")] static TEST_VECTOR_RISTRETTO255: &str = r#" { @@ -199,8 +200,8 @@ static TEST_VECTOR_P256: &str = r#" } "#; -#[cfg(all(feature = "x25519", feature = "ristretto255"))] -static TEST_VECTOR_X25519_RISTRETTO255: &str = r#" +#[cfg(all(feature = "curve25519", feature = "ristretto255"))] +static TEST_VECTOR_CURVE25519_RISTRETTO255: &str = r#" { "client_s_pk": "f535ff1f431781ebdf247ba474600b35900c78bae062b78bca336f93125fae78", "client_s_sk": "a2965d641d8faac6d78929faaea9d849260374dfbc48fcd8508d619e91549e0f", @@ -237,8 +238,8 @@ static TEST_VECTOR_X25519_RISTRETTO255: &str = r#" } "#; -#[cfg(feature = "x25519")] -static TEST_VECTOR_X25519_P256: &str = r#" +#[cfg(feature = "curve25519")] +static TEST_VECTOR_CURVE25519_P256: &str = r#" { "client_s_pk": "984c4d0154f43c559a6e9c11e53899796c14df117333d23415e6271694fad424", "client_s_sk": "2b3e92c34952a4c3deb75b18f9096d22256f54819f608e181720da0d48590108", @@ -276,7 +277,7 @@ static TEST_VECTOR_X25519_P256: &str = r#" "#; fn decode(values: &Value, key: &str) -> Option> { - values[key].as_str().and_then(|s| hex::decode(&s).ok()) + values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &Value) -> TestVectorParameters { @@ -682,19 +683,19 @@ fn generate_test_vectors() -> Result<(), ProtocolError> { let parameters = generate_parameters::()?; println!("P-256: {}", stringify_test_vectors(¶meters)); - #[cfg(all(feature = "x25519", feature = "ristretto255"))] + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] { - let parameters = generate_parameters::()?; + let parameters = generate_parameters::()?; println!( - "X25519 Ristretto255: {}", + "Curve25519 Ristretto255: {}", stringify_test_vectors(¶meters) ); } - #[cfg(feature = "x25519")] + #[cfg(feature = "curve25519")] { - let parameters = generate_parameters::()?; - println!("X25519 P-256: {}", stringify_test_vectors(¶meters)); + let parameters = generate_parameters::()?; + println!("Curve25519 P-256: {}", stringify_test_vectors(¶meters)); } Ok(()) @@ -732,10 +733,10 @@ fn test_registration_request() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -777,10 +778,10 @@ fn test_serialization() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -827,10 +828,10 @@ fn test_registration_response() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -890,10 +891,10 @@ fn test_registration_upload() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -934,10 +935,10 @@ fn test_password_file() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -986,10 +987,10 @@ fn test_credential_request() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -1065,10 +1066,10 @@ fn test_credential_response() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -1107,7 +1108,7 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { assert_eq!( hex::encode(¶meters.server_s_pk), - hex::encode(&client_login_finish_result.server_s_pk.serialize()) + hex::encode(client_login_finish_result.server_s_pk.serialize()) ); assert_eq!( hex::encode(¶meters.session_key), @@ -1128,10 +1129,10 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -1165,10 +1166,10 @@ fn test_server_login_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::(TEST_VECTOR_RISTRETTO255)?; inner::(TEST_VECTOR_P256)?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::(TEST_VECTOR_X25519_RISTRETTO255)?; - #[cfg(feature = "x25519")] - inner::(TEST_VECTOR_X25519_P256)?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::(TEST_VECTOR_CURVE25519_RISTRETTO255)?; + #[cfg(feature = "curve25519")] + inner::(TEST_VECTOR_CURVE25519_P256)?; Ok(()) } @@ -1252,10 +1253,10 @@ fn test_complete_flow_success() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] test_complete_flow::(b"good password", b"good password")?; test_complete_flow::(b"good password", b"good password")?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - test_complete_flow::(b"good password", b"good password")?; - #[cfg(feature = "x25519")] - test_complete_flow::(b"good password", b"good password")?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + test_complete_flow::(b"good password", b"good password")?; + #[cfg(feature = "curve25519")] + test_complete_flow::(b"good password", b"good password")?; Ok(()) } @@ -1265,10 +1266,10 @@ fn test_complete_flow_fail() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] test_complete_flow::(b"good password", b"bad password")?; test_complete_flow::(b"good password", b"bad password")?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - test_complete_flow::(b"good password", b"bad password")?; - #[cfg(feature = "x25519")] - test_complete_flow::(b"good password", b"bad password")?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + test_complete_flow::(b"good password", b"bad password")?; + #[cfg(feature = "curve25519")] + test_complete_flow::(b"good password", b"bad password")?; Ok(()) } @@ -1302,10 +1303,10 @@ fn test_zeroize_client_registration_start() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1350,10 +1351,10 @@ fn test_zeroize_client_registration_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1407,10 +1408,10 @@ fn test_zeroize_server_registration_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1463,10 +1464,10 @@ fn test_zeroize_client_login_start() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1527,10 +1528,10 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1617,10 +1618,10 @@ fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1689,10 +1690,10 @@ fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1742,10 +1743,10 @@ fn test_scalar_always_nonzero() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1800,10 +1801,10 @@ fn test_reflected_value_error_registration() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } @@ -1877,10 +1878,10 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> { #[cfg(feature = "ristretto255")] inner::()?; inner::()?; - #[cfg(all(feature = "x25519", feature = "ristretto255"))] - inner::()?; - #[cfg(feature = "x25519")] - inner::()?; + #[cfg(all(feature = "curve25519", feature = "ristretto255"))] + inner::()?; + #[cfg(feature = "curve25519")] + inner::()?; Ok(()) } diff --git a/src/tests/mock_rng.rs b/src/tests/mock_rng.rs index d6753384..e3d23943 100644 --- a/src/tests/mock_rng.rs +++ b/src/tests/mock_rng.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use core::cmp::min; use std::vec::Vec; @@ -50,7 +51,7 @@ impl RngCore for CycleRng { #[inline] fn fill_bytes(&mut self, dest: &mut [u8]) { let len = min(self.v.len(), dest.len()); - (&mut dest[..len]).copy_from_slice(&self.v[..len]); + dest[..len].copy_from_slice(&self.v[..len]); rotate_left(&mut self.v, len); } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 94863d52..0a87984c 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. mod full_test; pub mod mock_rng; diff --git a/src/tests/opaque_vectors.rs b/src/tests/opaque_vectors.rs index f35013f5..ec5795ca 100644 --- a/src/tests/opaque_vectors.rs +++ b/src/tests/opaque_vectors.rs @@ -1,12 +1,13 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. -//! The OPAQUE test vectors taken from https://github.com/cfrg/draft-irtf-cfrg-opaque/blob/master/draft-irtf-cfrg-opaque.md, -//! which are presented in https://www.ietf.org/archive/id/draft-irtf-cfrg-opaque-08.txt +//! The OPAQUE test vectors taken from , +//! which are presented in pub(crate) static VECTORS: &str = r#" ## Real Test Vectors {#real-vectors} diff --git a/src/tests/parser.rs b/src/tests/parser.rs index 26bb7caf..e1bf82cf 100644 --- a/src/tests/parser.rs +++ b/src/tests/parser.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use std::string::{String, ToString}; use std::vec::Vec; diff --git a/src/tests/test_opaque_vectors.rs b/src/tests/test_opaque_vectors.rs index 6cea9044..3f0d67a4 100644 --- a/src/tests/test_opaque_vectors.rs +++ b/src/tests/test_opaque_vectors.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. use core::ops::Add; use std::vec; @@ -35,6 +36,7 @@ use crate::tests::mock_rng::CycleRng; use crate::*; #[allow(non_snake_case)] +#[allow(dead_code)] #[derive(Debug)] pub struct OpaqueTestVectorParameters { pub dummy_private_key: Vec, @@ -92,7 +94,7 @@ macro_rules! parse_default { } fn decode(values: &JsonValue, key: &str) -> Option> { - values[key].as_str().and_then(|s| hex::decode(&s).ok()) + values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &JsonValue) -> OpaqueTestVectorParameters diff --git a/src/util.rs b/src/util.rs index 2aaff7d9..283713c2 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,9 +1,10 @@ -// Copyright (c) Facebook, Inc. and its affiliates. +// Copyright (c) Meta Platforms, Inc. and affiliates. // -// This source code is licensed under both the MIT license found in the -// LICENSE-MIT file in the root directory of this source tree and the Apache +// 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. +// of this source tree. You may select, at your option, one of the above-listed +// licenses. //! Utility functions.