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
|
||||
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:
|
||||
name: Test on ${{ matrix.target }} (using cross)
|
||||
runs-on: ubuntu-latest
|
||||
@@ -61,10 +67,10 @@ jobs:
|
||||
# Note: just use `cross` as you would `cargo`, but always
|
||||
# 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 std --features ${{ matrix.backend_feature }}
|
||||
|
||||
|
||||
slow-hash-test:
|
||||
name: Test on ${{ matrix.target }} with slow hash
|
||||
feature-test:
|
||||
name: Test on ${{ matrix.target }} with ${{ matrix.frontend_feature }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -73,26 +79,14 @@ jobs:
|
||||
- u64_backend
|
||||
- u32_backend
|
||||
- p256,u64_backend
|
||||
frontend_feature:
|
||||
- slow-hash
|
||||
- serialize
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
- run: cargo test --verbose --features slow-hash --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 }}
|
||||
|
||||
- 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 }}
|
||||
|
||||
simple-login-test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -142,6 +136,25 @@ jobs:
|
||||
- name: Run expect (which then runs cargo run)
|
||||
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:
|
||||
name: cargo bench compilation
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
+5
-3
@@ -3,6 +3,7 @@ name = "opaque-ke"
|
||||
version = "2.0.0-pre.1"
|
||||
repository = "https://github.com/novifinancial/opaque-ke"
|
||||
keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"]
|
||||
categories = ["no-std"]
|
||||
description = "An implementation of the OPAQUE password-authenticated key exchange protocol"
|
||||
authors = ["Kevin Lewi <[email protected]>", "François Garillot <[email protected]>"]
|
||||
license = "MIT"
|
||||
@@ -16,17 +17,19 @@ p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
||||
bench = []
|
||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
||||
std = ["curve25519-dalek/std"]
|
||||
serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"]
|
||||
|
||||
[dependencies]
|
||||
argon2 = { version = "0.2", optional = true }
|
||||
base64 = { version = "0.13", optional = true }
|
||||
constant_time_eq = "0.1"
|
||||
curve25519-dalek = { version = "3", default-features = false, features = ["std"] }
|
||||
curve25519-dalek = { version = "3", default-features = false }
|
||||
digest = "0.9"
|
||||
displaydoc = "0.2"
|
||||
generic-array = "0.14"
|
||||
generic-bytes = { version = "0.1" }
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
hkdf = "0.11"
|
||||
hmac = "0.11"
|
||||
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 }
|
||||
once_cell = { version = "1", 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 }
|
||||
subtle = { version = "2.3", default-features = false }
|
||||
thiserror = "1"
|
||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1"
|
||||
base64 = "0.13"
|
||||
bincode = "1"
|
||||
chacha20poly1305 = "0.8"
|
||||
|
||||
+3
-1
@@ -11,13 +11,15 @@ use crate::{
|
||||
keypair::{KeyPair, PrivateKey, PublicKey},
|
||||
opaque::{bytestrings_from_identifiers, Identifiers},
|
||||
};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryFrom;
|
||||
use digest::Digest;
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use generic_bytes::SizedBytes;
|
||||
use hkdf::Hkdf;
|
||||
use hmac::{Hmac, Mac, NewMac};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// Constant string used as salt for HKDF computation
|
||||
|
||||
+11
-7
@@ -4,9 +4,10 @@
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
//! 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::fmt::Debug;
|
||||
|
||||
use displaydoc::Display;
|
||||
|
||||
@@ -61,7 +62,7 @@ pub enum InternalPakeError<T = Infallible> {
|
||||
}
|
||||
|
||||
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 {
|
||||
Self::Custom(custom) => f.debug_tuple("InvalidByteSequence").field(custom).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 InternalPakeError {
|
||||
@@ -157,7 +159,7 @@ pub enum PakeError<T = Infallible> {
|
||||
}
|
||||
|
||||
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 {
|
||||
Self::CryptoError(internal_pake_error) => f
|
||||
.debug_tuple("CryptoError")
|
||||
@@ -177,6 +179,7 @@ impl<T: Debug> Debug for PakeError<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Error> Error for PakeError<T> {}
|
||||
|
||||
// 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> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::VerificationError(pake_error) => f
|
||||
.debug_tuple("VerificationError")
|
||||
@@ -247,6 +250,7 @@ impl<T: Debug> Debug for ProtocolError<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Error> Error for ProtocolError<T> {}
|
||||
|
||||
// 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
|
||||
// merged, and https://github.com/dtolnay/thiserror/issues/62 for why this
|
||||
// comes up in our doc tests.
|
||||
impl<T> From<::std::convert::Infallible> for ProtocolError<T> {
|
||||
fn from(_: ::std::convert::Infallible) -> Self {
|
||||
impl<T> From<::core::convert::Infallible> for ProtocolError<T> {
|
||||
fn from(_: ::core::convert::Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@
|
||||
use crate::errors::{InternalPakeError, ProtocolError};
|
||||
use crate::hash::Hash;
|
||||
use crate::serialization::i2osp;
|
||||
use alloc::vec::Vec;
|
||||
use digest::{BlockInput, Digest};
|
||||
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 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();
|
||||
h.update(&b[0]);
|
||||
@@ -76,7 +77,7 @@ mod tests {
|
||||
#[test]
|
||||
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
|
||||
let test_vectors: Vec<Params> = vec![
|
||||
let test_vectors: alloc::vec::Vec<Params> = alloc::vec![
|
||||
Params {
|
||||
msg: "",
|
||||
len_in_bytes: 0x20,
|
||||
|
||||
+2
-2
@@ -14,9 +14,9 @@ mod x25519;
|
||||
|
||||
use crate::errors::{InternalPakeError, ProtocolError};
|
||||
use crate::hash::Hash;
|
||||
use core::ops::Mul;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::ops::Mul;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// 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
|
||||
/// <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;
|
||||
|
||||
Ok([i2osp(mode as usize, 1)?, i2osp(Self::SUITE_ID, 2)?].concat())
|
||||
|
||||
+3
-3
@@ -11,6 +11,8 @@
|
||||
use super::Group;
|
||||
use crate::errors::{InternalPakeError, ProtocolError};
|
||||
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::{ArrayLength, GenericArray};
|
||||
use num_bigint::{BigInt, Sign};
|
||||
@@ -24,8 +26,6 @@ use p256_::elliptic_curve::subtle::ConstantTimeEq;
|
||||
use p256_::elliptic_curve::Field;
|
||||
use p256_::{AffinePoint, EncodedPoint, ProjectivePoint};
|
||||
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
|
||||
// `p: 2^256 - 2^224 + 2^192 + 2^96 - 1`
|
||||
@@ -411,7 +411,7 @@ mod tests {
|
||||
#[test]
|
||||
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
|
||||
let test_vectors: Vec<Params> = vec![
|
||||
let test_vectors = alloc::vec![
|
||||
Params {
|
||||
msg: "",
|
||||
px: "2c15230b26dbc6fc9a37051158c95b79656e17a1a920b11394ca91c44247d3e4",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
use super::Group;
|
||||
use crate::errors::{InternalPakeError, ProtocolError};
|
||||
use crate::hash::Hash;
|
||||
use core::convert::TryInto;
|
||||
use curve25519_dalek::{
|
||||
constants::RISTRETTO_BASEPOINT_POINT,
|
||||
ristretto::{CompressedRistretto, RistrettoPoint},
|
||||
@@ -14,7 +15,6 @@ use curve25519_dalek::{
|
||||
};
|
||||
use generic_array::{typenum::U32, GenericArray};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryInto;
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
/// The implementation of such a subgroup for Ristretto
|
||||
|
||||
+16
-16
@@ -5,10 +5,10 @@
|
||||
|
||||
macro_rules! impl_debug_eq_hash_for {
|
||||
(struct $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:ident$(, $field2:ident)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
||||
impl$(<$($gen$(: $bound)?),+>)? std::fmt::Debug for $name$(<$($gen),+>)?
|
||||
$(where $($type: std::fmt::Debug,)+)?
|
||||
impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)?
|
||||
$(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")
|
||||
.field("$field1", &self.$field1)
|
||||
$(.field("$field2", &self.$field2))*
|
||||
@@ -29,20 +29,20 @@ macro_rules! impl_debug_eq_hash_for {
|
||||
}
|
||||
}
|
||||
|
||||
impl$(<$($gen$(: $bound)?),+>)? std::hash::Hash for $name$(<$($gen),+>)?
|
||||
$(where $($type: std::hash::Hash,)+)?
|
||||
impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)?
|
||||
$(where $($type: core::hash::Hash,)+)?
|
||||
{
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::hash::Hash::hash(&self.$field1, state);
|
||||
$(std::hash::Hash::hash(&self.$field2, state);)*
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
core::hash::Hash::hash(&self.$field1, state);
|
||||
$(core::hash::Hash::hash(&self.$field2, state);)*
|
||||
}
|
||||
}
|
||||
};
|
||||
(tuple $name:ident$(<$($gen:ident$(: $bound:tt)?),+$(,)?>)?, [$field1:tt$(, $field2:tt)*$(,)?]$(, )?$([$($type:ty),+$(,)?]$(,)?)?) => {
|
||||
impl$(<$($gen$(: $bound)?),+>)? std::fmt::Debug for $name$(<$($gen),+>)?
|
||||
$(where $($type: std::fmt::Debug,)+)?
|
||||
impl$(<$($gen$(: $bound)?),+>)? core::fmt::Debug for $name$(<$($gen),+>)?
|
||||
$(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")
|
||||
.field(&self.$field1)
|
||||
$(.field(&self.$field2))*
|
||||
@@ -63,12 +63,12 @@ macro_rules! impl_debug_eq_hash_for {
|
||||
}
|
||||
}
|
||||
|
||||
impl$(<$($gen$(: $bound)?),+>)? std::hash::Hash for $name$(<$($gen),+>)?
|
||||
$(where $($type: std::hash::Hash,)+)?
|
||||
impl$(<$($gen$(: $bound)?),+>)? core::hash::Hash for $name$(<$($gen),+>)?
|
||||
$(where $($type: core::hash::Hash,)+)?
|
||||
{
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
std::hash::Hash::hash(&self.$field1, state);
|
||||
$(std::hash::Hash::hash(&self.$field2, state);)*
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
core::hash::Hash::hash(&self.$field1, state);
|
||||
$(core::hash::Hash::hash(&self.$field2, state);)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::{
|
||||
hash::Hash,
|
||||
keypair::{PrivateKey, PublicKey, SecretKey},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ use crate::{
|
||||
keypair::{KeyPair, PrivateKey, PublicKey, SecretKey, SizedBytesExt},
|
||||
serialization::serialize,
|
||||
};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryFrom;
|
||||
use digest::{Digest, FixedOutput};
|
||||
use generic_array::{
|
||||
typenum::{Unsigned, U32},
|
||||
@@ -27,7 +30,6 @@ use generic_bytes::SizedBytes;
|
||||
use hkdf::Hkdf;
|
||||
use hmac::{Hmac, Mac, NewMac};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
pub(crate) type NonceLen = U32;
|
||||
|
||||
+40
-34
@@ -9,17 +9,19 @@
|
||||
|
||||
use crate::errors::{InternalPakeError, ProtocolError};
|
||||
use crate::group::Group;
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Debug;
|
||||
use core::ops::Deref;
|
||||
#[cfg(test)]
|
||||
use generic_array::typenum::Unsigned;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use generic_bytes::{SizedBytes, TryFromSizedBytesError};
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
use proptest::prelude::*;
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
use rand::{rngs::StdRng, SeedableRng};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// 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> {
|
||||
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")
|
||||
.field("pk", &self.pk)
|
||||
.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> + std::hash::Hash> std::hash::Hash for KeyPair<G, S> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl<G: Group, S: SecretKey<G> + core::hash::Hash> core::hash::Hash for KeyPair<G, S> {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.pk.hash(state);
|
||||
self.sk.hash(state);
|
||||
}
|
||||
@@ -139,14 +141,14 @@ impl<G: Group> KeyPair<G> {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
|
||||
vec![
|
||||
alloc::vec![
|
||||
(self.pk.as_ptr(), G::ElemLen::to_usize()),
|
||||
(self.sk.as_ptr(), G::ScalarLen::to_usize()),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
impl<G: Group + Debug> KeyPair<G> {
|
||||
/// Test-only strategy returning a proptest Strategy based on
|
||||
/// generate_random
|
||||
@@ -179,7 +181,7 @@ impl<L: ArrayLength<u8>> Clone 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()
|
||||
}
|
||||
}
|
||||
@@ -192,8 +194,8 @@ impl<L: ArrayLength<u8>> PartialEq for Key<L> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: ArrayLength<u8>> std::hash::Hash for Key<L> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
impl<L: ArrayLength<u8>> core::hash::Hash for Key<L> {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
@@ -297,7 +299,7 @@ pub trait SecretKey<G: Group>: Clone + Sized + Zeroize {
|
||||
}
|
||||
|
||||
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> {
|
||||
let pk_data = GenericArray::<u8, G::ElemLen>::from_slice(&pk.0[..]);
|
||||
@@ -373,19 +375,20 @@ impl<G: Group> SizedBytes for PublicKey<G> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::errors::*;
|
||||
use core::slice::from_raw_parts;
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use generic_array::typenum::Unsigned;
|
||||
use rand::rngs::OsRng;
|
||||
use std::slice::from_raw_parts;
|
||||
|
||||
#[test]
|
||||
fn test_zeroize_key() -> Result<(), ProtocolError> {
|
||||
let key_len = <RistrettoPoint as Group>::ElemLen::to_usize();
|
||||
let mut key =
|
||||
Key::<<RistrettoPoint as Group>::ElemLen>(GenericArray::clone_from_slice(&vec![
|
||||
let mut key = Key::<<RistrettoPoint as Group>::ElemLen>(GenericArray::clone_from_slice(
|
||||
&alloc::vec![
|
||||
1u8;
|
||||
key_len
|
||||
]));
|
||||
],
|
||||
));
|
||||
let ptr = key.as_ptr();
|
||||
|
||||
key.zeroize();
|
||||
@@ -412,6 +415,7 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
proptest! {
|
||||
#[test]
|
||||
fn test_ristretto_check(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
|
||||
@@ -448,7 +452,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remote_key() -> anyhow::Result<()> {
|
||||
fn remote_key() {
|
||||
use crate::{
|
||||
CipherSuite, ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult,
|
||||
ClientLoginStartResult, ClientRegistration, ClientRegistrationFinishParameters,
|
||||
@@ -473,7 +477,7 @@ mod tests {
|
||||
struct RemoteKey(PrivateKey<RistrettoPoint>);
|
||||
|
||||
impl SecretKey<RistrettoPoint> for RemoteKey {
|
||||
type Error = std::convert::Infallible;
|
||||
type Error = core::convert::Infallible;
|
||||
|
||||
fn diffie_hellman(
|
||||
&self,
|
||||
@@ -502,27 +506,29 @@ mod tests {
|
||||
let sk = RistrettoPoint::random_nonzero_scalar(&mut OsRng);
|
||||
let sk_bytes = RistrettoPoint::scalar_as_bytes(sk);
|
||||
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 ClientRegistrationStartResult {
|
||||
message,
|
||||
state: client,
|
||||
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes())?;
|
||||
} = ClientRegistration::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||
let ServerRegistrationStartResult { message, .. } =
|
||||
ServerRegistration::start(&server_setup, message, &[])?;
|
||||
let ClientRegistrationFinishResult { message, .. } = client.finish(
|
||||
&mut OsRng,
|
||||
message,
|
||||
ClientRegistrationFinishParameters::Default,
|
||||
)?;
|
||||
ServerRegistration::start(&server_setup, message, &[]).unwrap();
|
||||
let ClientRegistrationFinishResult { message, .. } = client
|
||||
.finish(
|
||||
&mut OsRng,
|
||||
message,
|
||||
ClientRegistrationFinishParameters::Default,
|
||||
)
|
||||
.unwrap();
|
||||
let file = ServerRegistration::finish(message);
|
||||
|
||||
let ClientLoginStartResult {
|
||||
message,
|
||||
state: client,
|
||||
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes())?;
|
||||
} = ClientLogin::<Default>::start(&mut OsRng, PASSWORD.as_bytes()).unwrap();
|
||||
let ServerLoginStartResult {
|
||||
message,
|
||||
state: server,
|
||||
@@ -534,11 +540,11 @@ mod tests {
|
||||
message,
|
||||
&[],
|
||||
ServerLoginStartParameters::default(),
|
||||
)?;
|
||||
let ClientLoginFinishResult { message, .. } =
|
||||
client.finish(message, ClientLoginFinishParameters::Default)?;
|
||||
server.finish(message)?;
|
||||
|
||||
Ok(())
|
||||
)
|
||||
.unwrap();
|
||||
let ClientLoginFinishResult { message, .. } = client
|
||||
.finish(message, ClientLoginFinishParameters::Default)
|
||||
.unwrap();
|
||||
server.finish(message).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,6 +824,7 @@
|
||||
|
||||
#![cfg_attr(not(feature = "bench"), deny(missing_docs))]
|
||||
#![deny(unsafe_code)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(not(any(feature = "u64_backend", feature = "u32_backend",)))]
|
||||
compile_error!(
|
||||
@@ -831,6 +832,8 @@ compile_error!(
|
||||
please enable one of: u64_backend, u32_backend"
|
||||
);
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
// Error types
|
||||
pub mod errors;
|
||||
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use crate::{
|
||||
keypair::{KeyPair, PublicKey, SecretKey, SizedBytesExt},
|
||||
opaque::ServerSetup,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use digest::Digest;
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use generic_bytes::SizedBytes;
|
||||
@@ -197,7 +198,7 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
|
||||
rng: &mut R,
|
||||
server_setup: &ServerSetup<CS, S>,
|
||||
) -> 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);
|
||||
|
||||
Self {
|
||||
|
||||
+3
-1
@@ -19,12 +19,14 @@ use crate::{
|
||||
CredentialFinalization, CredentialRequest, CredentialResponse, RegistrationRequest,
|
||||
RegistrationResponse, RegistrationUpload,
|
||||
};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use digest::Digest;
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use generic_bytes::SizedBytes;
|
||||
use hkdf::Hkdf;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::marker::PhantomData;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
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
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Token<Grp: Group> {
|
||||
pub(crate) data: Vec<u8>,
|
||||
pub(crate) data: alloc::vec::Vec<u8>,
|
||||
pub(crate) blind: Grp::Scalar,
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ mod tests {
|
||||
#[test]
|
||||
fn oprf_inversion_unsalted() {
|
||||
let mut rng = OsRng;
|
||||
let mut input = vec![0u8; 64];
|
||||
let mut input = alloc::vec![0u8; 64];
|
||||
rng.fill_bytes(&mut input);
|
||||
let (token, alpha) = blind::<_, RistrettoPoint, sha2::Sha512>(&input, &mut rng).unwrap();
|
||||
let res =
|
||||
|
||||
+16
-15
@@ -4,10 +4,11 @@
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
use crate::errors::PakeError;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
// Corresponds to the I2OSP() function from RFC8017
|
||||
pub(crate) fn i2osp(input: usize, length: usize) -> Result<Vec<u8>, PakeError> {
|
||||
let sizeof_usize = std::mem::size_of::<usize>();
|
||||
pub(crate) fn i2osp(input: usize, length: usize) -> Result<alloc::vec::Vec<u8>, PakeError> {
|
||||
let sizeof_usize = core::mem::size_of::<usize>();
|
||||
|
||||
// Check if input >= 256^length
|
||||
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());
|
||||
}
|
||||
|
||||
let mut output = vec![0u8; length];
|
||||
let mut output = alloc::vec![0u8; length];
|
||||
output.splice(
|
||||
length - sizeof_usize..length,
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
let mut output_array = [0u8; std::mem::size_of::<usize>()];
|
||||
output_array[std::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
|
||||
let mut output_array = [0u8; core::mem::size_of::<usize>()];
|
||||
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
|
||||
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
|
||||
// (input, remainder)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -89,17 +90,17 @@ macro_rules! impl_serialize_and_deserialize_for {
|
||||
.map_err(serde::de::Error::custom)
|
||||
} else {
|
||||
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> {
|
||||
type Value = $t<CS>;
|
||||
fn expecting(
|
||||
&self,
|
||||
formatter: &mut std::fmt::Formatter,
|
||||
) -> std::fmt::Result {
|
||||
formatter.write_str(std::concat!(
|
||||
formatter: &mut core::fmt::Formatter,
|
||||
) -> core::fmt::Result {
|
||||
formatter.write_str(core::concat!(
|
||||
"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(|_| {
|
||||
serde::de::Error::invalid_value(
|
||||
serde::de::Unexpected::Bytes(value),
|
||||
&std::concat!(
|
||||
&core::concat!(
|
||||
"invalid byte sequence for ",
|
||||
std::stringify!($t)
|
||||
core::stringify!($t)
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
deserializer.deserialize_bytes(ByteVisitor::<CS> {
|
||||
marker: std::marker::PhantomData,
|
||||
marker: core::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ use crate::{
|
||||
serialization::{i2osp, os2ip, serialize},
|
||||
*,
|
||||
};
|
||||
#[cfg(test)]
|
||||
use alloc::vec;
|
||||
#[cfg(test)]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
||||
use generic_array::typenum::Unsigned;
|
||||
@@ -351,8 +355,8 @@ fn ke3_message_roundtrip() {
|
||||
proptest! {
|
||||
|
||||
#[test]
|
||||
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..std::mem::size_of::<usize>())) {
|
||||
assert_eq!(i2osp(os2ip(&bytes)?, bytes.len())?, bytes);
|
||||
fn test_i2osp_os2ip(bytes in vec(any::<u8>(), 0..core::mem::size_of::<usize>())) {
|
||||
assert_eq!(i2osp(os2ip(&bytes).unwrap(), bytes.len()).unwrap(), bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@
|
||||
//! Trait specifying a slow hashing function
|
||||
|
||||
use crate::{errors::InternalPakeError, hash::Hash};
|
||||
use alloc::vec::Vec;
|
||||
use digest::Digest;
|
||||
#[cfg(feature = "slow-hash")]
|
||||
use generic_array::typenum::Unsigned;
|
||||
@@ -36,7 +37,7 @@ impl<D: Hash> SlowHash<D> for argon2::Argon2<'_> {
|
||||
input: GenericArray<u8, <D as Digest>::OutputSize>,
|
||||
) -> Result<Vec<u8>, InternalPakeError> {
|
||||
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
|
||||
.hash_password_into(
|
||||
argon2::Algorithm::Argon2id,
|
||||
|
||||
+16
-14
@@ -6,22 +6,17 @@
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use crate::{
|
||||
ciphersuite::CipherSuite,
|
||||
errors::*,
|
||||
group::Group,
|
||||
key_exchange::tripledh::{NonceLen, TripleDH},
|
||||
keypair::KeyPair,
|
||||
opaque::*,
|
||||
slow_hash::NoOpHash,
|
||||
tests::mock_rng::CycleRng,
|
||||
*,
|
||||
ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, 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 generic_array::typenum::Unsigned;
|
||||
use generic_bytes::SizedBytes;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use rand::rngs::OsRng;
|
||||
use serde_json::Value;
|
||||
use std::slice::from_raw_parts;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
// Tests
|
||||
@@ -154,8 +149,9 @@ fn populate_test_vectors(values: &Value) -> TestVectorParameters {
|
||||
}
|
||||
}
|
||||
|
||||
fn stringify_test_vectors(p: &TestVectorParameters) -> String {
|
||||
let mut s = String::new();
|
||||
#[cfg(feature = "std")]
|
||||
fn stringify_test_vectors(p: &TestVectorParameters) -> alloc::string::String {
|
||||
let mut s = alloc::string::String::new();
|
||||
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_sk\": \"{}\",\n", hex::encode(&p.client_s_sk)).as_str());
|
||||
@@ -277,7 +273,12 @@ fn stringify_test_vectors(p: &TestVectorParameters) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
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;
|
||||
|
||||
// Inputs
|
||||
@@ -447,6 +448,7 @@ fn generate_parameters<CS: CipherSuite>() -> TestVectorParameters {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn generate_test_vectors() {
|
||||
let parameters = generate_parameters::<RistrettoSha5123dhNoSlowHash>();
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
// This source code is licensed under the MIT license found in the
|
||||
// LICENSE file in the root directory of this source tree.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::min;
|
||||
use rand::{CryptoRng, Error, RngCore};
|
||||
use std::cmp::min;
|
||||
|
||||
/// A simple implementation of `RngCore` for testing purposes.
|
||||
///
|
||||
|
||||
@@ -7,6 +7,9 @@ use crate::{
|
||||
ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, keypair::PrivateKey,
|
||||
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 generic_array::typenum::Unsigned;
|
||||
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![];
|
||||
for line in input.lines() {
|
||||
// If line contains colon, then
|
||||
|
||||
@@ -7,6 +7,8 @@ use crate::group::Group;
|
||||
use crate::hash::Hash;
|
||||
use crate::tests::mock_rng::CycleRng;
|
||||
use crate::{errors::*, oprf};
|
||||
use alloc::string::ToString;
|
||||
use alloc::vec::Vec;
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use generic_array::GenericArray;
|
||||
use serde_json::Value;
|
||||
|
||||
Reference in New Issue
Block a user