Repository: novifinancial/opaque-ke
Pull request #245 (2021-10-06 21:12:51)

Adding support for thumbv6m-none-eabi
Mirrors the changes from https://github.com/novifinancial/opaque-ke/pull/229/commits/c7e897b6a613450cde5667bf3a7984e7afa3625a for v1 branch


Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index d1b9b9c..0a3cde0 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -137,14 +137,18 @@ jobs:
         target:
           # for wasm
           - wasm32-unknown-unknown
+          # for any no_std target
+          - thumbv6m-none-eabi
         backend_feature:
           - u64_backend
           - u32_backend
+        frontend_feature:
+          - slow-hash
     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 }}
+      - run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }} --features ${{ matrix.backend_feature }}
 
   benches:
     name: cargo bench compilation
diff --git a/Cargo.toml b/Cargo.toml
index 4a0aa23..79bc88f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,11 +9,12 @@ authors = ["Kevin Lewi <klewi@fb.com>", "François Garillot <fga@fb.com>"]
 license = "MIT"
 edition = "2018"
 readme = "README.md"
+resolver = "2"
 
 [features]
 default = ["u64_backend"]
 slow-hash = ["scrypt"]
-std = ["curve25519-dalek/std"]
+std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng"]
 bench = []
 u64_backend = ["curve25519-dalek/u64_backend"]
 u32_backend = ["curve25519-dalek/u32_backend"]
@@ -22,18 +23,19 @@ u32_backend = ["curve25519-dalek/u32_backend"]
 constant_time_eq = "0.1"
 curve25519-dalek = { version = "3", default-features = false }
 digest = "0.9"
-displaydoc = "0.1"
+displaydoc = { version = "0.2", default-features = false }
 generic-array = "0.14"
-generic-bytes = { version = "0.1" }
-getrandom = { version = "0.2", features = ["js"] }
+getrandom = { version = "0.2", optional = true }
 hkdf = "0.11"
 hmac = "0.11"
-rand = "0.8"
-scrypt = { version = "0.5", optional = true }
+rand = { version = "0.8", default-features = false }
+scrypt = { version = "0.5", default-features = false, optional = true }
 subtle = { version = "2.3", default-features = false }
-thiserror = "1"
 zeroize = { version = "1", features = ["zeroize_derive"] }
 
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+getrandom = { version = "0.2", features = ["js"], optional = true }
+
 [dev-dependencies]
 anyhow = "1"
 base64 = "0.13"
@@ -41,6 +43,7 @@ chacha20poly1305 = "0.8"
 criterion = "0.3"
 hex = "0.4"
 lazy_static = "1"
+opaque-ke = { path = "", default-features = false, features = ["std"] }
 serde_json = "1"
 sha2 = "0.9"
 proptest = "1"
diff --git a/src/envelope.rs b/src/envelope.rs
index 59c49cc..646523a 100644
--- a/src/envelope.rs
+++ b/src/envelope.rs
@@ -14,7 +14,6 @@ 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};
@@ -27,13 +26,22 @@ const STR_EXPORT_KEY: &[u8] = b"ExportKey";
 
 const NONCE_LEN: usize = 32;
 
-#[derive(Clone, Copy, PartialEq, Zeroize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Zeroize)]
 #[zeroize(drop)]
 pub(crate) enum InnerEnvelopeMode {
     Base = 1,
     CustomIdentifier = 2,
 }
 
+impl InnerEnvelopeMode {
+    fn to_u8(&self) -> u8 {
+        match &self {
+            InnerEnvelopeMode::Base => 1,
+            InnerEnvelopeMode::CustomIdentifier => 2,
+        }
+    }
+}
+
 impl TryFrom<u8> for InnerEnvelopeMode {
     type Error = PakeError;
     fn try_from(x: u8) -> Result<Self, Self::Error> {
@@ -55,7 +63,7 @@ pub(crate) struct InnerEnvelope {
 
 impl InnerEnvelope {
     pub(crate) fn serialize(&self) -> Vec<u8> {
-        [&[self.mode as u8], &self.nonce[..], &self.ciphertext[..]].concat()
+        [&[self.mode.to_u8()], &self.nonce[..], &self.ciphertext[..]].concat()
     }
 
     pub(crate) fn deserialize(input: &[u8]) -> Result<(Self, Vec<u8>), ProtocolError> {
@@ -66,7 +74,7 @@ impl InnerEnvelope {
         }
         let mode = InnerEnvelopeMode::try_from(input[0])?;
 
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
 
         let bytes = &input[1..];
         if bytes.len() < NONCE_LEN + key_len {
@@ -126,15 +134,15 @@ pub(crate) struct OpenedInnerEnvelope<D: Hash> {
 
 impl<D: Hash> Envelope<D> {
     fn hmac_key_size() -> usize {
-        <D as Digest>::OutputSize::to_usize()
+        <D as Digest>::OutputSize::USIZE
     }
 
     fn export_key_size() -> usize {
-        <D as Digest>::OutputSize::to_usize()
+        <D as Digest>::OutputSize::USIZE
     }
 
     pub(crate) fn get_mode(&self) -> InnerEnvelopeMode {
-        self.inner_envelope.mode
+        self.inner_envelope.mode.clone()
     }
 
     /// The format of the output is:
@@ -250,7 +258,7 @@ impl<D: Hash> Envelope<D> {
         let aad = construct_aad(server_s_pk, optional_ids)?;
         let opened = self.open_raw(key, &aad)?;
 
-        if opened.plaintext.len() != <Key as SizedBytes>::Len::to_usize() {
+        if opened.plaintext.len() != Key::LEN {
             // Plaintext should consist of a single key
             return Err(InternalPakeError::UnexpectedEnvelopeContentsError.into());
         }
diff --git a/src/errors.rs b/src/errors.rs
index 5edc514..9f41348 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -37,23 +37,26 @@ pub enum InternalPakeError {
     HmacError,
     /// Computing the slow hashing function failed
     SlowHashError,
-    /// This error occurs when the envelope seal fails
     /// Constructing the envelope seal failed.
     SealError,
-    /// This error occurs when the envelope seal open fails
     /// Opening the envelope seal failed.
     SealOpenError,
-    /// This error occurs when the envelope seal open hmac check fails
     /// HMAC check in seal open failed.
     SealOpenHmacError,
-    /// This error occurs when the envelope cannot be constructed properly
-    /// based on the credentials that were specified to be required.
+    /**
+     * This error occurs when the envelope cannot be constructed properly
+     * based on the credentials that were specified to be required.
+     */
     InvalidEnvelopeStructureError,
-    /// This error occurs when attempting to open an envelope of the wrong
-    /// type (base mode, custom identifier)
+    /**
+     * This error occurs when attempting to open an envelope of the wrong
+     * type (base mode, custom identifier)
+     */
     IncompatibleEnvelopeModeError,
-    /// This error occurs when the envelope is opened and deserialization
-    /// fails
+    /**
+     * This error occurs when the envelope is opened and deserialization
+     * fails
+     */
     UnexpectedEnvelopeContentsError,
 }
 
@@ -63,11 +66,8 @@ impl Error for InternalPakeError {}
 /// Represents an error in password checking
 #[derive(Debug, Display)]
 pub enum PakeError {
-    /// This error results from an internal error during PRF construction
-    ///
     /// Internal error during PRF verification: {0}
     CryptoError(InternalPakeError),
-    /// This error occurs when the server object that is being called finish() on is malformed
     /// Incomplete set of keys passed into finish() function
     IncompleteKeysError,
     /// The provided server public key doesn't match the sealed one
@@ -96,21 +96,21 @@ impl Error for PakeError {}
 /// Represents an error in protocol handling
 #[derive(Debug, Display)]
 pub enum ProtocolError {
-    /// This error results from an error during password verification
-    ///
     /// Internal error during password verification: {0}
     VerificationError(PakeError),
-    /// This error occurs when the server answer cannot be handled
     /// Server response cannot be handled.
     ServerError,
-    /// This error occurs when the server specifies an envelope credentials
-    /// format that is invalid
+    /**
+     * This error occurs when the server specifies an envelope credentials
+     * format that is invalid
+     */
     ServerInvalidEnvelopeCredentialsFormatError,
-    /// This error occurs when the client request cannot be handled
     /// Client request cannot be handled.
     ClientError,
-    /// This error occurs when the client detects that the server has
-    /// reflected the OPRF value (beta == alpha)
+    /**
+     * This error occurs when the client detects that the server has
+     * reflected the OPRF value (beta == alpha)
+     */
     ReflectedValueError,
 }
 
@@ -142,24 +142,6 @@ impl From<::core::convert::Infallible> for ProtocolError {
     }
 }
 
-impl From<generic_bytes::TryFromSizedBytesError> for InternalPakeError {
-    fn from(_: generic_bytes::TryFromSizedBytesError) -> Self {
-        InternalPakeError::InvalidByteSequence
-    }
-}
-
-impl From<generic_bytes::TryFromSizedBytesError> for PakeError {
-    fn from(e: generic_bytes::TryFromSizedBytesError) -> Self {
-        PakeError::CryptoError(e.into())
-    }
-}
-
-impl From<generic_bytes::TryFromSizedBytesError> for ProtocolError {
-    fn from(e: generic_bytes::TryFromSizedBytesError) -> Self {
-        PakeError::CryptoError(e.into()).into()
-    }
-}
-
 pub(crate) mod utils {
     use super::*;
 
diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs
index 1a01449..5849521 100644
--- a/src/key_exchange/tripledh.rs
+++ b/src/key_exchange/tripledh.rs
@@ -12,7 +12,7 @@ use crate::{
     group::Group,
     hash::Hash,
     key_exchange::traits::{KeyExchange, ToBytes, ToBytesWithPointers},
-    keypair::{Key, KeyPair, SizedBytesExt},
+    keypair::{Key, KeyPair},
     serialization::{serialize, tokenize},
 };
 use alloc::vec::Vec;
@@ -22,7 +22,6 @@ use generic_array::{
     typenum::{Unsigned, U32},
     ArrayLength, GenericArray,
 };
-use generic_bytes::SizedBytes;
 use hkdf::Hkdf;
 use hmac::{Hmac, Mac, NewMac};
 use rand::{CryptoRng, RngCore};
@@ -278,10 +277,7 @@ impl ToBytesWithPointers for Ke1State {
     #[cfg(test)]
     fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
         alloc::vec![
-            (
-                self.client_e_sk.as_ptr(),
-                <Key as SizedBytes>::Len::to_usize(),
-            ),
+            (self.client_e_sk.as_ptr(), Key::LEN,),
             (self.client_nonce.as_ptr(), NonceLen::to_usize()),
         ]
     }
diff --git a/src/keypair.rs b/src/keypair.rs
index 649c5fc..08b498b 100644
--- a/src/keypair.rs
+++ b/src/keypair.rs
@@ -7,34 +7,15 @@
 
 #![allow(unsafe_code)]
 
-use crate::errors::InternalPakeError;
+use crate::errors::{InternalPakeError, PakeError};
 use crate::group::Group;
 use alloc::vec::Vec;
 use core::fmt::Debug;
 use core::marker::PhantomData;
-use core::ops::Deref;
-#[cfg(test)]
-use generic_array::typenum::Unsigned;
 use generic_array::{typenum::U32, GenericArray};
-use generic_bytes::{SizedBytes, TryFromSizedBytesError};
-#[cfg(all(test, feature = "std"))]
-use proptest::prelude::*;
-#[cfg(all(test, feature = "std"))]
-use rand::{rngs::StdRng, SeedableRng};
 use rand::{CryptoRng, RngCore};
 use zeroize::Zeroize;
 
-/// Convenience extension trait of SizedBytes
-pub trait SizedBytesExt: SizedBytes {
-    /// Convert from bytes
-    fn from_bytes(bytes: &[u8]) -> Result<Self, TryFromSizedBytesError> {
-        <Self as SizedBytes>::from_arr(GenericArray::from_slice(bytes))
-    }
-}
-
-// blanket implementation
-impl<T> SizedBytesExt for T where T: SizedBytes {}
-
 /// A Keypair trait with public-private verification
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct KeyPair<G> {
@@ -105,7 +86,7 @@ impl<G: Group> KeyPair<G> {
 
     /// Obtains a KeyPair from a slice representing the private key
     pub fn from_private_key_slice(input: &[u8]) -> Result<Self, InternalPakeError> {
-        let sk = Key::from_arr(GenericArray::from_slice(input))?;
+        let sk = Key(input.to_vec());
         let pk = Self::public_from_private(&sk);
         Ok(Self {
             pk,
@@ -117,17 +98,20 @@ impl<G: Group> KeyPair<G> {
     #[cfg(test)]
     pub fn as_byte_ptrs(&self) -> Vec<(*const u8, usize)> {
         alloc::vec![
-            (self.pk.as_ptr(), <Key as SizedBytes>::Len::to_usize()),
-            (self.sk.as_ptr(), <Key as SizedBytes>::Len::to_usize()),
+            (self.pk.0.as_ptr(), Key::LEN),
+            (self.sk.0.as_ptr(), Key::LEN),
         ]
     }
 }
 
-#[cfg(all(test, feature = "std"))]
+#[cfg(test)]
 impl<G: Group + Debug> KeyPair<G> {
     /// Test-only strategy returning a proptest Strategy based on
     /// generate_random
-    fn uniform_keypair_strategy() -> BoxedStrategy<Self> {
+    fn uniform_keypair_strategy() -> proptest::prelude::BoxedStrategy<Self> {
+        use proptest::prelude::*;
+        use rand::{rngs::StdRng, SeedableRng};
+
         // The no_shrink is because keypairs should be fixed -- shrinking would cause a different
         // keypair to be generated, which appears to not be very useful.
         any::<[u8; 32]>()
@@ -147,7 +131,7 @@ impl<G: Group + Debug> KeyPair<G> {
 #[repr(transparent)]
 pub struct Key(Vec<u8>);
 
-impl Deref for Key {
+impl core::ops::Deref for Key {
     type Target = Vec<u8>;
 
     fn deref(&self) -> &Self::Target {
@@ -155,15 +139,22 @@ impl Deref for Key {
     }
 }
 
-impl SizedBytes for Key {
-    type Len = U32;
+impl Key {
+    pub(crate) const LEN: usize = 32;
 
-    fn to_arr(&self) -> GenericArray<u8, Self::Len> {
-        GenericArray::clone_from_slice(&self.0[..])
+    /// Convert to bytes
+    pub fn to_arr(&self) -> GenericArray<u8, U32> {
+        GenericArray::clone_from_slice(&self.0)
     }
 
-    fn from_arr(key_bytes: &GenericArray<u8, Self::Len>) -> Result<Self, TryFromSizedBytesError> {
-        Ok(Key(key_bytes.to_vec()))
+    /// Convert from bytes
+    pub fn from_bytes(input: &[u8]) -> Result<Self, PakeError> {
+        if input.len() != Self::LEN {
+            return Err(PakeError::SerializationError);
+        }
+        Ok(Self(
+            GenericArray::<u8, U32>::clone_from_slice(input).to_vec(),
+        ))
     }
 }
 
@@ -173,14 +164,14 @@ mod tests {
     use crate::errors::*;
     use core::slice::from_raw_parts;
     use curve25519_dalek::ristretto::RistrettoPoint;
-    use generic_array::typenum::Unsigned;
+    use proptest::prelude::*;
     use rand::rngs::OsRng;
 
     #[test]
     fn test_zeroize_key() -> Result<(), ProtocolError> {
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
         let mut key = Key(alloc::vec![1u8; key_len]);
-        let ptr = key.as_ptr();
+        let ptr = key.0.as_ptr();
 
         key.zeroize();
 
@@ -233,10 +224,10 @@ mod tests {
 
         #[test]
         fn test_private_key_slice(kp in KeyPair::<RistrettoPoint>::uniform_keypair_strategy()) {
-            let sk_bytes = kp.private().to_vec();
+            let sk_bytes = kp.private().0.clone();
 
             let kp2 = KeyPair::<RistrettoPoint>::from_private_key_slice(&sk_bytes)?;
-            let kp2_private_bytes = kp2.private().to_vec();
+            let kp2_private_bytes = kp2.private().0.clone();
 
             prop_assert_eq!(sk_bytes, kp2_private_bytes);
         }
diff --git a/src/messages.rs b/src/messages.rs
index 29b8bf5..e758782 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -14,12 +14,11 @@ use crate::{
     },
     group::Group,
     key_exchange::traits::{KeyExchange, ToBytes},
-    keypair::{Key, KeyPair, SizedBytesExt},
+    keypair::{Key, KeyPair},
 };
 use alloc::vec::Vec;
 use core::convert::TryFrom;
 use generic_array::{typenum::Unsigned, GenericArray};
-use generic_bytes::SizedBytes;
 
 // Messages
 // =========
@@ -86,7 +85,7 @@ impl<CS: CipherSuite> RegistrationResponse<CS> {
     /// Deserialization from bytes
     pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
         let elem_len = <CS::Group as Group>::ElemLen::to_usize();
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
         let checked_slice =
             check_slice_size(input, elem_len + key_len, "registration_response_bytes")?;
 
@@ -143,7 +142,7 @@ impl<CS: CipherSuite> RegistrationUpload<CS> {
 
     /// Deserialization from bytes
     pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
 
         let checked_slice = check_slice_size_atleast(input, key_len, "registration_upload_bytes")?;
 
@@ -246,7 +245,7 @@ impl<CS: CipherSuite> CredentialResponse<CS> {
     /// Deserialization from bytes
     pub fn deserialize(input: &[u8]) -> Result<Self, ProtocolError> {
         let elem_len = <CS::Group as Group>::ElemLen::to_usize();
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
         let checked_slice =
             check_slice_size_atleast(input, elem_len + key_len, "login_second_message_bytes")?;
 
diff --git a/src/opaque.rs b/src/opaque.rs
index 2b42ca4..ebd38b3 100644
--- a/src/opaque.rs
+++ b/src/opaque.rs
@@ -12,7 +12,7 @@ use crate::{
     group::Group,
     hash::Hash,
     key_exchange::traits::{KeyExchange, ToBytesWithPointers},
-    keypair::{Key, KeyPair, SizedBytesExt},
+    keypair::{Key, KeyPair},
     map_to_curve::GroupWithMapToCurve,
     oprf,
     serialization::{serialize, tokenize},
@@ -24,7 +24,6 @@ use alloc::vec::Vec;
 use core::{convert::TryFrom, marker::PhantomData};
 use digest::Digest;
 use generic_array::{typenum::Unsigned, GenericArray};
-use generic_bytes::SizedBytes;
 use rand::{CryptoRng, RngCore};
 use zeroize::Zeroize;
 
@@ -275,7 +274,7 @@ impl<CS: CipherSuite> ServerRegistration<CS> {
         }
 
         // Need to do this check manually because envelope is variable-size
-        let key_len = <Key as SizedBytes>::Len::to_usize();
+        let key_len = Key::LEN;
 
         let checked_bytes =
             check_slice_size_atleast(input, scalar_len + key_len, "server_registration_bytes")?;


Test patch:
diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs
index b513eb4..0477420 100644
--- a/src/serialization/tests.rs
+++ b/src/serialization/tests.rs
@@ -24,7 +24,6 @@ use alloc::vec::Vec;
 
 use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
 use generic_array::typenum::Unsigned;
-use generic_bytes::SizedBytes;
 use proptest::{collection::vec, prelude::*};
 use rand::{rngs::OsRng, RngCore};
 
diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs
index 4847baf..8b68035 100644
--- a/src/tests/full_test.rs
+++ b/src/tests/full_test.rs
@@ -6,14 +6,8 @@
 #![allow(unsafe_code)]
 
 use crate::{
-    ciphersuite::CipherSuite,
-    errors::*,
-    key_exchange::tripledh::TripleDH,
-    keypair::{Key, SizedBytesExt},
-    opaque::*,
-    slow_hash::NoOpHash,
-    tests::mock_rng::CycleRng,
-    *,
+    ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, keypair::Key, opaque::*,
+    slow_hash::NoOpHash, tests::mock_rng::CycleRng, *,
 };
 
 #[cfg(feature = "std")]
@@ -30,7 +24,6 @@ use alloc::vec;
 use alloc::vec::Vec;
 use core::slice::from_raw_parts;
 use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
-use generic_bytes::SizedBytes;
 use rand::rngs::OsRng;
 use serde_json::Value;
 use zeroize::Zeroize;
diff --git a/src/tests/opaque_test_vectors.rs b/src/tests/opaque_test_vectors.rs
index 7e31587..3fb3ea3 100644
--- a/src/tests/opaque_test_vectors.rs
+++ b/src/tests/opaque_test_vectors.rs
@@ -4,14 +4,8 @@
 // LICENSE file in the root directory of this source tree.
 
 use crate::{
-    ciphersuite::CipherSuite,
-    errors::*,
-    key_exchange::tripledh::TripleDH,
-    keypair::{Key, SizedBytesExt},
-    opaque::*,
-    slow_hash::NoOpHash,
-    tests::mock_rng::CycleRng,
-    *,
+    ciphersuite::CipherSuite, errors::*, key_exchange::tripledh::TripleDH, keypair::Key, opaque::*,
+    slow_hash::NoOpHash, tests::mock_rng::CycleRng, *,
 };
 use alloc::string::String;
 use alloc::string::ToString;