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:
daxpedda
2021-08-11 21:25:07 -07:00
committed by GitHub
co-authored by Kevin Lewi
parent 88673d8e05
commit 8a7bcf9097
23 changed files with 179 additions and 128 deletions
+33 -20
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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",
+1 -1
View File
@@ -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
View File
@@ -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);)*
}
}
};
+1
View File
@@ -10,6 +10,7 @@ use crate::{
hash::Hash,
keypair::{PrivateKey, PublicKey, SecretKey},
};
use alloc::vec::Vec;
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
+3 -1
View File
@@ -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
View File
@@ -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();
}
}
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
})
}
}
+6 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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>();
+2 -1
View File
@@ -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.
///
+4 -1
View File
@@ -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
+2
View File
@@ -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;