no_std support (#225)
* No std implementation * Run tests with std * Adding wasm32-unknown-unknown target Co-authored-by: Kevin Lewi <[email protected]>
This commit is contained in:
+33
-20
@@ -41,6 +41,12 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: --no-default-features --features ${{ matrix.backend_feature }}
|
args: --no-default-features --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
|
- name: Run cargo test with std
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --no-default-features --features std --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
cross-test:
|
cross-test:
|
||||||
name: Test on ${{ matrix.target }} (using cross)
|
name: Test on ${{ matrix.target }} (using cross)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -61,10 +67,10 @@ jobs:
|
|||||||
# Note: just use `cross` as you would `cargo`, but always
|
# Note: just use `cross` as you would `cargo`, but always
|
||||||
# pass the `--target=${{ matrix.target }}` arg. (Yes, really).
|
# pass the `--target=${{ matrix.target }}` arg. (Yes, really).
|
||||||
- run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.backend_feature }}
|
- run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.backend_feature }}
|
||||||
|
- run: cross test --verbose --target=${{ matrix.target }} --no-default-features --features std --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
|
feature-test:
|
||||||
slow-hash-test:
|
name: Test on ${{ matrix.target }} with ${{ matrix.frontend_feature }}
|
||||||
name: Test on ${{ matrix.target }} with slow hash
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -73,26 +79,14 @@ jobs:
|
|||||||
- u64_backend
|
- u64_backend
|
||||||
- u32_backend
|
- u32_backend
|
||||||
- p256,u64_backend
|
- p256,u64_backend
|
||||||
|
frontend_feature:
|
||||||
|
- slow-hash
|
||||||
|
- serialize
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: hecrj/setup-rust-action@v1
|
- uses: hecrj/setup-rust-action@v1
|
||||||
- run: cargo test --verbose --features slow-hash --no-default-features --features ${{ matrix.backend_feature }}
|
- run: cargo test --verbose --features ${{ matrix.frontend_feature }} --no-default-features --features ${{ matrix.backend_feature }}
|
||||||
|
- run: cargo test --verbose --features ${{ matrix.frontend_feature }},std --no-default-features --features ${{ matrix.backend_feature }}
|
||||||
serde-test:
|
|
||||||
name: Test on ${{ matrix.target }} with serde support
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
backend_feature:
|
|
||||||
- u64_backend
|
|
||||||
- u32_backend
|
|
||||||
- p256,u64_backend
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: hecrj/setup-rust-action@v1
|
|
||||||
- run: cargo test --verbose --features serialize --no-default-features --features ${{ matrix.backend_feature }}
|
|
||||||
|
|
||||||
|
|
||||||
simple-login-test:
|
simple-login-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -142,6 +136,25 @@ jobs:
|
|||||||
- name: Run expect (which then runs cargo run)
|
- name: Run expect (which then runs cargo run)
|
||||||
run: expect -f scripts/digital_locker.exp
|
run: expect -f scripts/digital_locker.exp
|
||||||
|
|
||||||
|
build-no-std:
|
||||||
|
name: Build with no-std on ${{ matrix.target }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
# for wasm
|
||||||
|
- wasm32-unknown-unknown
|
||||||
|
backend_feature:
|
||||||
|
- u64_backend
|
||||||
|
- u32_backend
|
||||||
|
- p256,u64_backend
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: hecrj/setup-rust-action@v1
|
||||||
|
- run: rustup target add ${{ matrix.target }}
|
||||||
|
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
benches:
|
benches:
|
||||||
name: cargo bench compilation
|
name: cargo bench compilation
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
+5
-3
@@ -3,6 +3,7 @@ name = "opaque-ke"
|
|||||||
version = "2.0.0-pre.1"
|
version = "2.0.0-pre.1"
|
||||||
repository = "https://github.com/novifinancial/opaque-ke"
|
repository = "https://github.com/novifinancial/opaque-ke"
|
||||||
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
|
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
|
||||||
|
categories = ["no-std"]
|
||||||
description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
|
description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
|
||||||
authors = ["Kevin Lewi <[email protected]>", "François Garillot <[email protected]>"]
|
authors = ["Kevin Lewi <[email protected]>", "François Garillot <[email protected]>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -16,17 +17,19 @@ p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
|||||||
bench = []
|
bench = []
|
||||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
u64_backend = ["curve25519-dalek/u64_backend"]
|
||||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
u32_backend = ["curve25519-dalek/u32_backend"]
|
||||||
|
std = ["curve25519-dalek/std"]
|
||||||
serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"]
|
serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
argon2 = { version = "0.2", optional = true }
|
argon2 = { version = "0.2", optional = true }
|
||||||
base64 = { version = "0.13", optional = true }
|
base64 = { version = "0.13", optional = true }
|
||||||
constant_time_eq = "0.1"
|
constant_time_eq = "0.1"
|
||||||
curve25519-dalek = { version = "3", default-features = false, features = ["std"] }
|
curve25519-dalek = { version = "3", default-features = false }
|
||||||
digest = "0.9"
|
digest = "0.9"
|
||||||
displaydoc = "0.2"
|
displaydoc = "0.2"
|
||||||
generic-array = "0.14"
|
generic-array = "0.14"
|
||||||
generic-bytes = { version = "0.1" }
|
generic-bytes = { version = "0.1" }
|
||||||
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
hkdf = "0.11"
|
hkdf = "0.11"
|
||||||
hmac = "0.11"
|
hmac = "0.11"
|
||||||
num-bigint = { version = "0.4", optional = true }
|
num-bigint = { version = "0.4", optional = true }
|
||||||
@@ -34,14 +37,13 @@ num-integer = { version = "0.1", optional = true }
|
|||||||
num-traits = { version = "0.2", optional = true }
|
num-traits = { version = "0.2", optional = true }
|
||||||
once_cell = { version = "1", optional = true }
|
once_cell = { version = "1", optional = true }
|
||||||
p256_ = { package = "p256", version = "0.9", optional = true }
|
p256_ = { package = "p256", version = "0.9", optional = true }
|
||||||
rand = "0.8"
|
rand = { version = "0.8", default-features = false }
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
subtle = { version = "2.3", default-features = false }
|
subtle = { version = "2.3", default-features = false }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1"
|
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bincode = "1"
|
bincode = "1"
|
||||||
chacha20poly1305 = "0.8"
|
chacha20poly1305 = "0.8"
|
||||||
|
|||||||
+3
-1
@@ -11,13 +11,15 @@ use crate::{
|
|||||||
keypair::{KeyPair, PrivateKey, PublicKey},
|
keypair::{KeyPair, PrivateKey, PublicKey},
|
||||||
opaque::{bytestrings_from_identifiers, Identifiers},
|
opaque::{bytestrings_from_identifiers, Identifiers},
|
||||||
};
|
};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::convert::TryFrom;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use generic_array::{typenum::Unsigned, GenericArray};
|
use generic_array::{typenum::Unsigned, GenericArray};
|
||||||
use generic_bytes::SizedBytes;
|
use generic_bytes::SizedBytes;
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use hmac::{Hmac, Mac, NewMac};
|
use hmac::{Hmac, Mac, NewMac};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::convert::TryFrom;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
// Constant string used as salt for HKDF computation
|
// Constant string used as salt for HKDF computation
|
||||||
|
|||||||
+11
-7
@@ -4,9 +4,10 @@
|
|||||||
// LICENSE file in the root directory of this source tree.
|
// LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
//! A list of error types which are produced during an execution of the protocol
|
//! A list of error types which are produced during an execution of the protocol
|
||||||
use std::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use displaydoc::Display;
|
use displaydoc::Display;
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ pub enum InternalPakeError<T = Infallible> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for InternalPakeError<T> {
|
impl<T: Debug> Debug for InternalPakeError<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Custom(custom) => f.debug_tuple("InvalidByteSequence").field(custom).finish(),
|
Self::Custom(custom) => f.debug_tuple("InvalidByteSequence").field(custom).finish(),
|
||||||
Self::InvalidByteSequence => f.debug_tuple("InvalidByteSequence").finish(),
|
Self::InvalidByteSequence => f.debug_tuple("InvalidByteSequence").finish(),
|
||||||
@@ -98,6 +99,7 @@ impl<T: Debug> Debug for InternalPakeError<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
impl<T: Error> Error for InternalPakeError<T> {}
|
impl<T: Error> Error for InternalPakeError<T> {}
|
||||||
|
|
||||||
impl InternalPakeError {
|
impl InternalPakeError {
|
||||||
@@ -157,7 +159,7 @@ pub enum PakeError<T = Infallible> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for PakeError<T> {
|
impl<T: Debug> Debug for PakeError<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::CryptoError(internal_pake_error) => f
|
Self::CryptoError(internal_pake_error) => f
|
||||||
.debug_tuple("CryptoError")
|
.debug_tuple("CryptoError")
|
||||||
@@ -177,6 +179,7 @@ impl<T: Debug> Debug for PakeError<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
impl<T: Error> Error for PakeError<T> {}
|
impl<T: Error> Error for PakeError<T> {}
|
||||||
|
|
||||||
// This is meant to express future(ly) non-trivial ways of converting the
|
// This is meant to express future(ly) non-trivial ways of converting the
|
||||||
@@ -230,7 +233,7 @@ pub enum ProtocolError<T = Infallible> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for ProtocolError<T> {
|
impl<T: Debug> Debug for ProtocolError<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::VerificationError(pake_error) => f
|
Self::VerificationError(pake_error) => f
|
||||||
.debug_tuple("VerificationError")
|
.debug_tuple("VerificationError")
|
||||||
@@ -247,6 +250,7 @@ impl<T: Debug> Debug for ProtocolError<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
impl<T: Error> Error for ProtocolError<T> {}
|
impl<T: Error> Error for ProtocolError<T> {}
|
||||||
|
|
||||||
// This is meant to express future(ly) non-trivial ways of converting the
|
// This is meant to express future(ly) non-trivial ways of converting the
|
||||||
@@ -268,8 +272,8 @@ impl<T> From<InternalPakeError<T>> for ProtocolError<T> {
|
|||||||
// See https://github.com/rust-lang/rust/issues/64715 and remove this when
|
// See https://github.com/rust-lang/rust/issues/64715 and remove this when
|
||||||
// merged, and https://github.com/dtolnay/thiserror/issues/62 for why this
|
// merged, and https://github.com/dtolnay/thiserror/issues/62 for why this
|
||||||
// comes up in our doc tests.
|
// comes up in our doc tests.
|
||||||
impl<T> From<::std::convert::Infallible> for ProtocolError<T> {
|
impl<T> From<::core::convert::Infallible> for ProtocolError<T> {
|
||||||
fn from(_: ::std::convert::Infallible) -> Self {
|
fn from(_: ::core::convert::Infallible) -> Self {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,7 @@
|
|||||||
use crate::errors::{InternalPakeError, ProtocolError};
|
use crate::errors::{InternalPakeError, ProtocolError};
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
use crate::serialization::i2osp;
|
use crate::serialization::i2osp;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use digest::{BlockInput, Digest};
|
use digest::{BlockInput, Digest};
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ pub fn expand_message_xmd<H: Hash>(
|
|||||||
let l_i_b_str = i2osp(len_in_bytes, 2)?;
|
let l_i_b_str = i2osp(len_in_bytes, 2)?;
|
||||||
let msg_prime = [&z_pad, msg, &l_i_b_str, &i2osp(0, 1)?, &dst_prime].concat();
|
let msg_prime = [&z_pad, msg, &l_i_b_str, &i2osp(0, 1)?, &dst_prime].concat();
|
||||||
|
|
||||||
let mut b: Vec<Vec<u8>> = vec![H::digest(&msg_prime).to_vec()]; // b[0]
|
let mut b: Vec<Vec<u8>> = alloc::vec![H::digest(&msg_prime).to_vec()]; // b[0]
|
||||||
|
|
||||||
let mut h = H::new();
|
let mut h = H::new();
|
||||||
h.update(&b[0]);
|
h.update(&b[0]);
|
||||||
@@ -76,7 +77,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_expand_message_xmd() {
|
fn test_expand_message_xmd() {
|
||||||
// Test vectors taken from Section K.1 of https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
// Test vectors taken from Section K.1 of https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
||||||
let test_vectors: Vec<Params> = vec![
|
let test_vectors: alloc::vec::Vec<Params> = alloc::vec![
|
||||||
Params {
|
Params {
|
||||||
msg: "",
|
msg: "",
|
||||||
len_in_bytes: 0x20,
|
len_in_bytes: 0x20,
|
||||||
|
|||||||
+2
-2
@@ -14,9 +14,9 @@ mod x25519;
|
|||||||
|
|
||||||
use crate::errors::{InternalPakeError, ProtocolError};
|
use crate::errors::{InternalPakeError, ProtocolError};
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
|
use core::ops::Mul;
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::ops::Mul;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
/// A prime-order subgroup of a base field (EC, prime-order field ...). This
|
/// A prime-order subgroup of a base field (EC, prime-order field ...). This
|
||||||
@@ -34,7 +34,7 @@ pub trait Group: Copy + Sized + for<'a> Mul<&'a <Self as Group>::Scalar, Output
|
|||||||
|
|
||||||
/// Generates the contextString parameter as defined in
|
/// Generates the contextString parameter as defined in
|
||||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-05.txt>
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-05.txt>
|
||||||
fn get_context_string(mode: u8) -> Result<Vec<u8>, ProtocolError> {
|
fn get_context_string(mode: u8) -> Result<alloc::vec::Vec<u8>, ProtocolError> {
|
||||||
use crate::serialization::i2osp;
|
use crate::serialization::i2osp;
|
||||||
|
|
||||||
Ok([i2osp(mode as usize, 1)?, i2osp(Self::SUITE_ID, 2)?].concat())
|
Ok([i2osp(mode as usize, 1)?, i2osp(Self::SUITE_ID, 2)?].concat())
|
||||||
|
|||||||
+3
-3
@@ -11,6 +11,8 @@
|
|||||||
use super::Group;
|
use super::Group;
|
||||||
use crate::errors::{InternalPakeError, ProtocolError};
|
use crate::errors::{InternalPakeError, ProtocolError};
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
|
use core::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
|
use core::str::FromStr;
|
||||||
use generic_array::typenum::{U32, U33};
|
use generic_array::typenum::{U32, U33};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use num_bigint::{BigInt, Sign};
|
use num_bigint::{BigInt, Sign};
|
||||||
@@ -24,8 +26,6 @@ use p256_::elliptic_curve::subtle::ConstantTimeEq;
|
|||||||
use p256_::elliptic_curve::Field;
|
use p256_::elliptic_curve::Field;
|
||||||
use p256_::{AffinePoint, EncodedPoint, ProjectivePoint};
|
use p256_::{AffinePoint, EncodedPoint, ProjectivePoint};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2
|
||||||
// `p: 2^256 - 2^224 + 2^192 + 2^96 - 1`
|
// `p: 2^256 - 2^224 + 2^192 + 2^96 - 1`
|
||||||
@@ -411,7 +411,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn map_to_curve_simple_swu() {
|
fn map_to_curve_simple_swu() {
|
||||||
// Test vectors taken from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-J.1.1
|
// Test vectors taken from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-J.1.1
|
||||||
let test_vectors: Vec<Params> = vec![
|
let test_vectors = alloc::vec![
|
||||||
Params {
|
Params {
|
||||||
msg: "",
|
msg: "",
|
||||||
px: "2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4",
|
px: "2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
use super::Group;
|
use super::Group;
|
||||||
use crate::errors::{InternalPakeError, ProtocolError};
|
use crate::errors::{InternalPakeError, ProtocolError};
|
||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
|
use core::convert::TryInto;
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
constants::RISTRETTO_BASEPOINT_POINT,
|
constants::RISTRETTO_BASEPOINT_POINT,
|
||||||
ristretto::{CompressedRistretto, RistrettoPoint},
|
ristretto::{CompressedRistretto, RistrettoPoint},
|
||||||
@@ -14,7 +15,6 @@ use curve25519_dalek::{
|
|||||||
};
|
};
|
||||||
use generic_array::{typenum::U32, GenericArray};
|
use generic_array::{typenum::U32, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::convert::TryInto;
|
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
/// The implementation of such a subgroup for Ristretto
|
/// The implementation of such a subgroup for Ristretto
|
||||||
|
|||||||
+16
-16
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
macro_rules! impl_debug_eq_hash_for {
|
macro_rules! impl_debug_eq_hash_for {
|
||||||
(struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
(struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
||||||
impl$(<$($gen$(: $bound)?),+>)? std::fmt::Debug for $name$(<$($gen),+>)?
|
impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)?
|
||||||
$(where $($type: std::fmt::Debug,)+)?
|
$(where $($type: core::fmt::Debug,)+)?
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("$name")
|
f.debug_struct("$name")
|
||||||
.field("$field1", &self.$field1)
|
.field("$field1", &self.$field1)
|
||||||
$(.field("$field2", &self.$field2))*
|
$(.field("$field2", &self.$field2))*
|
||||||
@@ -29,20 +29,20 @@ macro_rules! impl_debug_eq_hash_for {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl$(<$($gen$(: $bound)?),+>)? std::hash::Hash for $name$(<$($gen),+>)?
|
impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)?
|
||||||
$(where $($type: std::hash::Hash,)+)?
|
$(where $($type: core::hash::Hash,)+)?
|
||||||
{
|
{
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
std::hash::Hash::hash(&self.$field1, state);
|
core::hash::Hash::hash(&self.$field1, state);
|
||||||
$(std::hash::Hash::hash(&self.$field2, state);)*
|
$(core::hash::Hash::hash(&self.$field2, state);)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(tuple $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
(tuple $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
||||||
impl$(<$($gen$(: $bound)?),+>)? std::fmt::Debug for $name$(<$($gen),+>)?
|
impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)?
|
||||||
$(where $($type: std::fmt::Debug,)+)?
|
$(where $($type: core::fmt::Debug,)+)?
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_tuple("$name")
|
f.debug_tuple("$name")
|
||||||
.field(&self.$field1)
|
.field(&self.$field1)
|
||||||
$(.field(&self.$field2))*
|
$(.field(&self.$field2))*
|
||||||
@@ -63,12 +63,12 @@ macro_rules! impl_debug_eq_hash_for {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl$(<$($gen$(: $bound)?),+>)? std::hash::Hash for $name$(<$($gen),+>)?
|
impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)?
|
||||||
$(where $($type: std::hash::Hash,)+)?
|
$(where $($type: core::hash::Hash,)+)?
|
||||||
{
|
{
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
std::hash::Hash::hash(&self.$field1, state);
|
core::hash::Hash::hash(&self.$field1, state);
|
||||||
$(std::hash::Hash::hash(&self.$field2, state);)*
|
$(core::hash::Hash::hash(&self.$field2, state);)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::{
|
|||||||
hash::Hash,
|
hash::Hash,
|
||||||
keypair::{PrivateKey, PublicKey, SecretKey},
|
keypair::{PrivateKey, PublicKey, SecretKey},
|
||||||
};
|
};
|
||||||
|
use alloc::vec::Vec;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ use crate::{
|
|||||||
keypair::{KeyPair, PrivateKey, PublicKey, SecretKey, SizedBytesExt},
|
keypair::{KeyPair, PrivateKey, PublicKey, SecretKey, SizedBytesExt},
|
||||||
serialization::serialize,
|
serialization::serialize,
|
||||||
};
|
};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::convert::TryFrom;
|
||||||
use digest::{Digest, FixedOutput};
|
use digest::{Digest, FixedOutput};
|
||||||
use generic_array::{
|
use generic_array::{
|
||||||
typenum::{Unsigned, U32},
|
typenum::{Unsigned, U32},
|
||||||
@@ -27,7 +30,6 @@ use generic_bytes::SizedBytes;
|
|||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use hmac::{Hmac, Mac, NewMac};
|
use hmac::{Hmac, Mac, NewMac};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::convert::TryFrom;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
pub(crate) type NonceLen = U32;
|
pub(crate) type NonceLen = U32;
|
||||||
|
|||||||
+40
-34
@@ -9,17 +9,19 @@
|
|||||||
|
|
||||||
use crate::errors::{InternalPakeError, ProtocolError};
|
use crate::errors::{InternalPakeError, ProtocolError};
|
||||||
use crate::group::Group;
|
use crate::group::Group;
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
use core::ops::Deref;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use generic_bytes::{SizedBytes, TryFromSizedBytesError};
|
use generic_bytes::{SizedBytes, TryFromSizedBytesError};
|
||||||
#[cfg(test)]
|
#[cfg(all(test, feature = "std"))]
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
#[cfg(test)]
|
#[cfg(all(test, feature = "std"))]
|
||||||
use rand::{rngs::StdRng, SeedableRng};
|
use rand::{rngs::StdRng, SeedableRng};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
/// Convenience extension trait of SizedBytes
|
/// Convenience extension trait of SizedBytes
|
||||||
@@ -57,7 +59,7 @@ impl<G: Group, S: SecretKey<G>> Clone for KeyPair<G, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group, S: SecretKey<G> + Debug> Debug for KeyPair<G, S> {
|
impl<G: Group, S: SecretKey<G> + Debug> Debug for KeyPair<G, S> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_struct("KeyPair")
|
f.debug_struct("KeyPair")
|
||||||
.field("pk", &self.pk)
|
.field("pk", &self.pk)
|
||||||
.field("sk", &self.sk)
|
.field("sk", &self.sk)
|
||||||
@@ -73,8 +75,8 @@ impl<G: Group, S: SecretKey<G> + PartialEq> PartialEq for KeyPair<G, S> {
|
|||||||
|
|
||||||
impl<G: Group, S: SecretKey<G> + Eq> Eq for KeyPair<G, S> {}
|
impl<G: Group, S: SecretKey<G> + Eq> Eq for KeyPair<G, S> {}
|
||||||
|
|
||||||
impl<G: Group, S: SecretKey<G> + std::hash::Hash> std::hash::Hash for KeyPair<G, S> {
|
impl<G: Group, S: SecretKey<G> + core::hash::Hash> core::hash::Hash for KeyPair<G, S> {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.pk.hash(state);
|
self.pk.hash(state);
|
||||||
self.sk.hash(state);
|
self.sk.hash(state);
|
||||||
}
|
}
|
||||||
@@ -139,14 +141,14 @@ impl<G: Group> KeyPair<G> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
|
pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
|
||||||
vec![
|
alloc::vec![
|
||||||
(self.pk.as_ptr(), G::ElemLen::to_usize()),
|
(self.pk.as_ptr(), G::ElemLen::to_usize()),
|
||||||
(self.sk.as_ptr(), G::ScalarLen::to_usize()),
|
(self.sk.as_ptr(), G::ScalarLen::to_usize()),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(all(test, feature = "std"))]
|
||||||
impl<G: Group + Debug> KeyPair<G> {
|
impl<G: Group + Debug> KeyPair<G> {
|
||||||
/// Test-only strategy returning a proptest Strategy based on
|
/// Test-only strategy returning a proptest Strategy based on
|
||||||
/// generate_random
|
/// generate_random
|
||||||
@@ -179,7 +181,7 @@ impl<L: ArrayLength<u8>> Clone for Key<L> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<L: ArrayLength<u8>> Debug for Key<L> {
|
impl<L: ArrayLength<u8>> Debug for Key<L> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
f.debug_tuple("Key").field(&self.0).finish()
|
f.debug_tuple("Key").field(&self.0).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,8 +194,8 @@ impl<L: ArrayLength<u8>> PartialEq for Key<L> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: ArrayLength<u8>> std::hash::Hash for Key<L> {
|
impl<L: ArrayLength<u8>> core::hash::Hash for Key<L> {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.0.hash(state);
|
self.0.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +299,7 @@ pub trait SecretKey<G: Group>: Clone + Sized + Zeroize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Group> SecretKey<G> for PrivateKey<G> {
|
impl<G: Group> SecretKey<G> for PrivateKey<G> {
|
||||||
type Error = std::convert::Infallible;
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
fn diffie_hellman(&self, pk: PublicKey<G>) -> Result<Vec<u8>, InternalPakeError> {
|
fn diffie_hellman(&self, pk: PublicKey<G>) -> Result<Vec<u8>, InternalPakeError> {
|
||||||
let pk_data = GenericArray::<u8, G::ElemLen>::from_slice(&pk.0[..]);
|
let pk_data = GenericArray::<u8, G::ElemLen>::from_slice(&pk.0[..]);
|
||||||
@@ -373,19 +375,20 @@ impl<G: Group> SizedBytes for PublicKey<G> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
|
use core::slice::from_raw_parts;
|
||||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::slice::from_raw_parts;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_zeroize_key() -> Result<(), ProtocolError> {
|
fn test_zeroize_key() -> Result<(), ProtocolError> {
|
||||||
let key_len = <RistrettoPoint as Group>::ElemLen::to_usize();
|
let key_len = <RistrettoPoint as Group>::ElemLen::to_usize();
|
||||||
let mut key =
|
let mut key = Key::<<RistrettoPoint as Group>::ElemLen>(GenericArray::clone_from_slice(
|
||||||
Key::<<RistrettoPoint as Group>::ElemLen>(GenericArray::clone_from_slice(&vec![
|
&alloc::vec![
|
||||||
1u8;
|
1u8;
|
||||||
key_len
|
key_len
|
||||||
]));
|
],
|
||||||
|
));
|
||||||
let ptr = key.as_ptr();
|
let ptr = key.as_ptr();
|
||||||
|
|
||||||
key.zeroize();
|
key.zeroize();
|
||||||
@@ -412,6 +415,7 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
proptest! {
|
proptest! {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ristretto_check(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
fn test_ristretto_check(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
||||||
@@ -448,7 +452,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remote_key() -> anyhow::Result<()> {
|
fn remote_key() {
|
||||||
use crate::{
|
use crate::{
|
||||||
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
|
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
|
||||||
ClientLoginStartResult, ClientRegistration, ClientRegistrationFinishParameters,
|
ClientLoginStartResult, ClientRegistration, ClientRegistrationFinishParameters,
|
||||||
@@ -473,7 +477,7 @@ mod tests {
|
|||||||
struct RemoteKey(PrivateKey<RistrettoPoint>);
|
struct RemoteKey(PrivateKey<RistrettoPoint>);
|
||||||
|
|
||||||
impl SecretKey<RistrettoPoint> for RemoteKey {
|
impl SecretKey<RistrettoPoint> for RemoteKey {
|
||||||
type Error = std::convert::Infallible;
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
fn diffie_hellman(
|
fn diffie_hellman(
|
||||||
&self,
|
&self,
|
||||||
@@ -502,27 +506,29 @@ mod tests {
|
|||||||
let sk = RistrettoPoint::random_nonzero_scalar(&mut OsRng);
|
let sk = RistrettoPoint::random_nonzero_scalar(&mut OsRng);
|
||||||
let sk_bytes = RistrettoPoint::scalar_as_bytes(sk);
|
let sk_bytes = RistrettoPoint::scalar_as_bytes(sk);
|
||||||
let sk = RemoteKey(PrivateKey::from_arr(&sk_bytes).unwrap());
|
let sk = RemoteKey(PrivateKey::from_arr(&sk_bytes).unwrap());
|
||||||
let keypair = KeyPair::from_private_key(sk)?;
|
let keypair = KeyPair::from_private_key(sk).unwrap();
|
||||||
|
|
||||||
let server_setup = ServerSetup::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair);
|
let server_setup = ServerSetup::<Default, RemoteKey>::new_with_key(&mut OsRng, keypair);
|
||||||
|
|
||||||
let ClientRegistrationStartResult {
|
let ClientRegistrationStartResult {
|
||||||
message,
|
message,
|
||||||
state: client,
|
state: client,
|
||||||
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes())?;
|
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||||
let ServerRegistrationStartResult { message, .. } =
|
let ServerRegistrationStartResult { message, .. } =
|
||||||
ServerRegistration::start(&server_setup, message, &[])?;
|
ServerRegistration::start(&server_setup, message, &[]).unwrap();
|
||||||
let ClientRegistrationFinishResult { message, .. } = client.finish(
|
let ClientRegistrationFinishResult { message, .. } = client
|
||||||
&mut OsRng,
|
.finish(
|
||||||
message,
|
&mut OsRng,
|
||||||
ClientRegistrationFinishParameters::Default,
|
message,
|
||||||
)?;
|
ClientRegistrationFinishParameters::Default,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let file = ServerRegistration::finish(message);
|
let file = ServerRegistration::finish(message);
|
||||||
|
|
||||||
let ClientLoginStartResult {
|
let ClientLoginStartResult {
|
||||||
message,
|
message,
|
||||||
state: client,
|
state: client,
|
||||||
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes())?;
|
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||||
let ServerLoginStartResult {
|
let ServerLoginStartResult {
|
||||||
message,
|
message,
|
||||||
state: server,
|
state: server,
|
||||||
@@ -534,11 +540,11 @@ mod tests {
|
|||||||
message,
|
message,
|
||||||
&[],
|
&[],
|
||||||
ServerLoginStartParameters::default(),
|
ServerLoginStartParameters::default(),
|
||||||
)?;
|
)
|
||||||
let ClientLoginFinishResult { message, .. } =
|
.unwrap();
|
||||||
client.finish(message, ClientLoginFinishParameters::Default)?;
|
let ClientLoginFinishResult { message, .. } = client
|
||||||
server.finish(message)?;
|
.finish(message, ClientLoginFinishParameters::Default)
|
||||||
|
.unwrap();
|
||||||
Ok(())
|
server.finish(message).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -824,6 +824,7 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
#[cfg(not(any(feature = "u64_backend", feature = "u32_backend",)))]
|
#[cfg(not(any(feature = "u64_backend", feature = "u32_backend",)))]
|
||||||
compile_error!(
|
compile_error!(
|
||||||
@@ -831,6 +832,8 @@ compile_error!(
|
|||||||
please enable one of: u64_backend, u32_backend"
|
please enable one of: u64_backend, u32_backend"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
// Error types
|
// Error types
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ use crate::{
|
|||||||
keypair::{KeyPair, PublicKey, SecretKey, SizedBytesExt},
|
keypair::{KeyPair, PublicKey, SecretKey, SizedBytesExt},
|
||||||
opaque::ServerSetup,
|
opaque::ServerSetup,
|
||||||
};
|
};
|
||||||
|
use alloc::vec::Vec;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use generic_array::{typenum::Unsigned, GenericArray};
|
use generic_array::{typenum::Unsigned, GenericArray};
|
||||||
use generic_bytes::SizedBytes;
|
use generic_bytes::SizedBytes;
|
||||||
@@ -197,7 +198,7 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
|
|||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
server_setup: &ServerSetup<CS, S>,
|
server_setup: &ServerSetup<CS, S>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut masking_key = vec![0u8; <CS::Hash as Digest>::OutputSize::to_usize()];
|
let mut masking_key = alloc::vec![0u8; <CS::Hash as Digest>::OutputSize::to_usize()];
|
||||||
rng.fill_bytes(&mut masking_key);
|
rng.fill_bytes(&mut masking_key);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
+3
-1
@@ -19,12 +19,14 @@ use crate::{
|
|||||||
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
|
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
|
||||||
RegistrationResponse, RegistrationUpload,
|
RegistrationResponse, RegistrationUpload,
|
||||||
};
|
};
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::marker::PhantomData;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use generic_array::{typenum::Unsigned, GenericArray};
|
use generic_array::{typenum::Unsigned, GenericArray};
|
||||||
use generic_bytes::SizedBytes;
|
use generic_bytes::SizedBytes;
|
||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::marker::PhantomData;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
const STR_CREDENTIAL_RESPONSE_PAD: &[u8] = b"CredentialResponsePad";
|
const STR_CREDENTIAL_RESPONSE_PAD: &[u8] = b"CredentialResponsePad";
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ use rand::{CryptoRng, RngCore};
|
|||||||
/// Used to store the OPRF input and blinding factor
|
/// Used to store the OPRF input and blinding factor
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct Token<Grp: Group> {
|
pub struct Token<Grp: Group> {
|
||||||
pub(crate) data: Vec<u8>,
|
pub(crate) data: alloc::vec::Vec<u8>,
|
||||||
pub(crate) blind: Grp::Scalar,
|
pub(crate) blind: Grp::Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn oprf_inversion_unsalted() {
|
fn oprf_inversion_unsalted() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let mut input = vec![0u8; 64];
|
let mut input = alloc::vec![0u8; 64];
|
||||||
rng.fill_bytes(&mut input);
|
rng.fill_bytes(&mut input);
|
||||||
let (token, alpha) = blind::<_, RistrettoPoint, sha2::Sha512>(&input, &mut rng).unwrap();
|
let (token, alpha) = blind::<_, RistrettoPoint, sha2::Sha512>(&input, &mut rng).unwrap();
|
||||||
let res =
|
let res =
|
||||||
|
|||||||
+16
-15
@@ -4,10 +4,11 @@
|
|||||||
// LICENSE file in the root directory of this source tree.
|
// LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
use crate::errors::PakeError;
|
use crate::errors::PakeError;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
// Corresponds to the I2OSP() function from RFC8017
|
// Corresponds to the I2OSP() function from RFC8017
|
||||||
pub(crate) fn i2osp(input: usize, length: usize) -> Result<Vec<u8>, PakeError> {
|
pub(crate) fn i2osp(input: usize, length: usize) -> Result<alloc::vec::Vec<u8>, PakeError> {
|
||||||
let sizeof_usize = std::mem::size_of::<usize>();
|
let sizeof_usize = core::mem::size_of::<usize>();
|
||||||
|
|
||||||
// Check if input >= 256^length
|
// Check if input >= 256^length
|
||||||
if (sizeof_usize as u32 - input.leading_zeros() / 8) > length as u32 {
|
if (sizeof_usize as u32 - input.leading_zeros() / 8) > length as u32 {
|
||||||
@@ -18,7 +19,7 @@ pub(crate) fn i2osp(input: usize, length: usize) -> Result<Vec<u8>, PakeError> {
|
|||||||
return Ok((&input.to_be_bytes()[sizeof_usize - length..]).to_vec());
|
return Ok((&input.to_be_bytes()[sizeof_usize - length..]).to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = vec![0u8; length];
|
let mut output = alloc::vec![0u8; length];
|
||||||
output.splice(
|
output.splice(
|
||||||
length - sizeof_usize..length,
|
length - sizeof_usize..length,
|
||||||
input.to_be_bytes().iter().cloned(),
|
input.to_be_bytes().iter().cloned(),
|
||||||
@@ -28,12 +29,12 @@ pub(crate) fn i2osp(input: usize, length: usize) -> Result<Vec<u8>, PakeError> {
|
|||||||
|
|
||||||
// Corresponds to the OS2IP() function from RFC8017
|
// Corresponds to the OS2IP() function from RFC8017
|
||||||
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, PakeError> {
|
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, PakeError> {
|
||||||
if input.len() > std::mem::size_of::<usize>() {
|
if input.len() > core::mem::size_of::<usize>() {
|
||||||
return Err(PakeError::SerializationError);
|
return Err(PakeError::SerializationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output_array = [0u8; std::mem::size_of::<usize>()];
|
let mut output_array = [0u8; core::mem::size_of::<usize>()];
|
||||||
output_array[std::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
|
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
|
||||||
Ok(usize::from_be_bytes(output_array))
|
Ok(usize::from_be_bytes(output_array))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ pub(crate) fn serialize(input: &[u8], max_bytes: usize) -> Result<Vec<u8>, PakeE
|
|||||||
// Tokenizes an input of the format I2OSP(len(input), max_bytes) || input, outputting
|
// Tokenizes an input of the format I2OSP(len(input), max_bytes) || input, outputting
|
||||||
// (input, remainder)
|
// (input, remainder)
|
||||||
pub(crate) fn tokenize(input: &[u8], size_bytes: usize) -> Result<(Vec<u8>, Vec<u8>), PakeError> {
|
pub(crate) fn tokenize(input: &[u8], size_bytes: usize) -> Result<(Vec<u8>, Vec<u8>), PakeError> {
|
||||||
if size_bytes > std::mem::size_of::<usize>() || input.len() < size_bytes {
|
if size_bytes > core::mem::size_of::<usize>() || input.len() < size_bytes {
|
||||||
return Err(PakeError::SerializationError);
|
return Err(PakeError::SerializationError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,17 +90,17 @@ macro_rules! impl_serialize_and_deserialize_for {
|
|||||||
.map_err(serde::de::Error::custom)
|
.map_err(serde::de::Error::custom)
|
||||||
} else {
|
} else {
|
||||||
struct ByteVisitor<CS: CipherSuite> {
|
struct ByteVisitor<CS: CipherSuite> {
|
||||||
marker: std::marker::PhantomData<CS>,
|
marker: core::marker::PhantomData<CS>,
|
||||||
}
|
}
|
||||||
impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor<CS> {
|
impl<'de, CS: CipherSuite> serde::de::Visitor<'de> for ByteVisitor<CS> {
|
||||||
type Value = $t<CS>;
|
type Value = $t<CS>;
|
||||||
fn expecting(
|
fn expecting(
|
||||||
&self,
|
&self,
|
||||||
formatter: &mut std::fmt::Formatter,
|
formatter: &mut core::fmt::Formatter,
|
||||||
) -> std::fmt::Result {
|
) -> core::fmt::Result {
|
||||||
formatter.write_str(std::concat!(
|
formatter.write_str(core::concat!(
|
||||||
"the byte representation of a ",
|
"the byte representation of a ",
|
||||||
std::stringify!($t)
|
core::stringify!($t)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,16 +111,16 @@ macro_rules! impl_serialize_and_deserialize_for {
|
|||||||
$t::<CS>::deserialize(value).map_err(|_| {
|
$t::<CS>::deserialize(value).map_err(|_| {
|
||||||
serde::de::Error::invalid_value(
|
serde::de::Error::invalid_value(
|
||||||
serde::de::Unexpected::Bytes(value),
|
serde::de::Unexpected::Bytes(value),
|
||||||
&std::concat!(
|
&core::concat!(
|
||||||
"invalid byte sequence for ",
|
"invalid byte sequence for ",
|
||||||
std::stringify!($t)
|
core::stringify!($t)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deserializer.deserialize_bytes(ByteVisitor::<CS> {
|
deserializer.deserialize_bytes(ByteVisitor::<CS> {
|
||||||
marker: std::marker::PhantomData,
|
marker: core::marker::PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ use crate::{
|
|||||||
serialization::{i2osp, os2ip, serialize},
|
serialization::{i2osp, os2ip, serialize},
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
#[cfg(test)]
|
||||||
|
use alloc::vec;
|
||||||
|
#[cfg(test)]
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
@@ -351,8 +355,8 @@ fn ke3_message_roundtrip() {
|
|||||||
proptest! {
|
proptest! {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..std::mem::size_of::<usize>())) {
|
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..core::mem::size_of::<usize>())) {
|
||||||
assert_eq!(i2osp(os2ip(&bytes)?, bytes.len())?, bytes);
|
assert_eq!(i2osp(os2ip(&bytes).unwrap(), bytes.len()).unwrap(), bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,7 @@
|
|||||||
//! Trait specifying a slow hashing function
|
//! Trait specifying a slow hashing function
|
||||||
|
|
||||||
use crate::{errors::InternalPakeError, hash::Hash};
|
use crate::{errors::InternalPakeError, hash::Hash};
|
||||||
|
use alloc::vec::Vec;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
#[cfg(feature = "slow-hash")]
|
#[cfg(feature = "slow-hash")]
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
@@ -36,7 +37,7 @@ impl<D: Hash> SlowHash<D> for argon2::Argon2<'_> {
|
|||||||
input: GenericArray<u8, <D as Digest>::OutputSize>,
|
input: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||||
) -> Result<Vec<u8>, InternalPakeError> {
|
) -> Result<Vec<u8>, InternalPakeError> {
|
||||||
let params = argon2::Argon2::default();
|
let params = argon2::Argon2::default();
|
||||||
let mut output = vec![0u8; <D as Digest>::OutputSize::to_usize()];
|
let mut output = alloc::vec![0u8; <D as Digest>::OutputSize::to_usize()];
|
||||||
params
|
params
|
||||||
.hash_password_into(
|
.hash_password_into(
|
||||||
argon2::Algorithm::Argon2id,
|
argon2::Algorithm::Argon2id,
|
||||||
|
|||||||
+16
-14
@@ -6,22 +6,17 @@
|
|||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ciphersuite::CipherSuite,
|
ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, opaque::*,
|
||||||
errors::*,
|
slow_hash::NoOpHash, tests::mock_rng::CycleRng, *,
|
||||||
group::Group,
|
|
||||||
key_exchange::tripledh::{NonceLen, TripleDH},
|
|
||||||
keypair::KeyPair,
|
|
||||||
opaque::*,
|
|
||||||
slow_hash::NoOpHash,
|
|
||||||
tests::mock_rng::CycleRng,
|
|
||||||
*,
|
|
||||||
};
|
};
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use alloc::vec;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::slice::from_raw_parts;
|
||||||
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
||||||
use generic_array::typenum::Unsigned;
|
|
||||||
use generic_bytes::SizedBytes;
|
use generic_bytes::SizedBytes;
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::rngs::OsRng;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::slice::from_raw_parts;
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
@@ -154,8 +149,9 @@ fn populate_test_vectors(values: &Value) -> TestVectorParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stringify_test_vectors(p: &TestVectorParameters) -> String {
|
#[cfg(feature = "std")]
|
||||||
let mut s = String::new();
|
fn stringify_test_vectors(p: &TestVectorParameters) -> alloc::string::String {
|
||||||
|
let mut s = alloc::string::String::new();
|
||||||
s.push_str("{\n");
|
s.push_str("{\n");
|
||||||
s.push_str(format!("\"client_s_pk\": \"{}\",\n", hex::encode(&p.client_s_pk)).as_str());
|
s.push_str(format!("\"client_s_pk\": \"{}\",\n", hex::encode(&p.client_s_pk)).as_str());
|
||||||
s.push_str(format!("\"client_s_sk\": \"{}\",\n", hex::encode(&p.client_s_sk)).as_str());
|
s.push_str(format!("\"client_s_sk\": \"{}\",\n", hex::encode(&p.client_s_sk)).as_str());
|
||||||
@@ -277,7 +273,12 @@ fn stringify_test_vectors(p: &TestVectorParameters) -> String {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
||||||
|
use crate::{group::Group, key_exchange::tripledh::NonceLen, keypair::KeyPair};
|
||||||
|
use generic_array::typenum::Unsigned;
|
||||||
|
use rand::RngCore;
|
||||||
|
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
@@ -447,6 +448,7 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
#[test]
|
#[test]
|
||||||
fn generate_test_vectors() {
|
fn generate_test_vectors() {
|
||||||
let parameters = generate_parameters::<RistrettoSha5123dhNoSlowHash>();
|
let parameters = generate_parameters::<RistrettoSha5123dhNoSlowHash>();
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
// This source code is licensed under the MIT license found in the
|
// This source code is licensed under the MIT license found in the
|
||||||
// LICENSE file in the root directory of this source tree.
|
// LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::cmp::min;
|
||||||
use rand::{CryptoRng, Error, RngCore};
|
use rand::{CryptoRng, Error, RngCore};
|
||||||
use std::cmp::min;
|
|
||||||
|
|
||||||
/// A simple implementation of `RngCore` for testing purposes.
|
/// A simple implementation of `RngCore` for testing purposes.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ use crate::{
|
|||||||
ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, keypair::PrivateKey,
|
ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, keypair::PrivateKey,
|
||||||
opaque::*, slow_hash::NoOpHash, tests::mock_rng::CycleRng, *,
|
opaque::*, slow_hash::NoOpHash, tests::mock_rng::CycleRng, *,
|
||||||
};
|
};
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use alloc::{format, vec};
|
||||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
use generic_array::typenum::Unsigned;
|
use generic_array::typenum::Unsigned;
|
||||||
use generic_bytes::SizedBytes;
|
use generic_bytes::SizedBytes;
|
||||||
@@ -711,7 +714,7 @@ macro_rules! rfc_to_params {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rfc_to_json(input: &str) -> String {
|
fn rfc_to_json(input: &str) -> alloc::string::String {
|
||||||
let mut json = vec![];
|
let mut json = vec![];
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
// If line contains colon, then
|
// If line contains colon, then
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use crate::group::Group;
|
|||||||
use crate::hash::Hash;
|
use crate::hash::Hash;
|
||||||
use crate::tests::mock_rng::CycleRng;
|
use crate::tests::mock_rng::CycleRng;
|
||||||
use crate::{errors::*, oprf};
|
use crate::{errors::*, oprf};
|
||||||
|
use alloc::string::ToString;
|
||||||
|
use alloc::vec::Vec;
|
||||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|||||||
Reference in New Issue
Block a user