From 230b1bcef6a33c53dc9f44bbfce891c213c975cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Tue, 3 Nov 2020 21:44:00 +0000 Subject: [PATCH] Start integrating the derivable SizedBytes - just derive it on Key and KeyPair for now --- Cargo.lock | 22 ++++++++ Cargo.toml | 2 + src/errors.rs | 20 +++++++ src/group.rs | 1 + src/key_exchange/tripledh.rs | 3 +- src/keypair.rs | 103 +++++++---------------------------- src/lib.rs | 18 +++--- src/opaque.rs | 9 +-- src/serialization/tests.rs | 3 +- src/tests/opaque_ke_test.rs | 3 +- 10 files changed, 84 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2dab8d2..95d3d43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -335,6 +335,26 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-bytes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6638d839bbd1cea640d8c5348dd82e0d545dbd364f3c2a251646eaf2ef0773b" +dependencies = [ + "generic-array", +] + +[[package]] +name = "generic-bytes-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4257fe99e64e321c197164da8ae22f7a3c074a5b2519072866e2d38bc1ca59e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "getrandom" version = "0.1.14" @@ -518,6 +538,8 @@ dependencies = [ "displaydoc", "fiat-crypto", "generic-array", + "generic-bytes", + "generic-bytes-derive", "hex", "hkdf", "hmac 0.9.0", diff --git a/Cargo.toml b/Cargo.toml index 3f5cdc6..6eb7168 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ digest = "0.9.0" displaydoc = "0.1.7" fiat-crypto = { version = "0.1.5"} generic-array = "0.14.4" +generic-bytes = { version = "0.1.0" } +generic-bytes-derive = { version = "0.1.0" } hkdf = "0.9.0" hmac = "0.9.0" rand_core = "0.5.1" diff --git a/src/errors.rs b/src/errors.rs index 359ad13..7fb161f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -10,6 +10,8 @@ use thiserror::Error; /// Represents an error in the manipulation of internal cryptographic data #[derive(Debug, Display, Error)] pub enum InternalPakeError { + /// Deserializing from a byte sequence failed + InvalidByteSequence, /// Invalid length for {name}: expected {len}, but is actually {actual_len}. SizeError { /// name @@ -116,6 +118,24 @@ impl From<::std::convert::Infallible> for ProtocolError { } } +impl From for InternalPakeError { + fn from(_: generic_bytes::TryFromSizedBytesError) -> Self { + InternalPakeError::InvalidByteSequence + } +} + +impl From for PakeError { + fn from(e: generic_bytes::TryFromSizedBytesError) -> Self { + PakeError::CryptoError(e.into()) + } +} + +impl From for ProtocolError { + fn from(e: generic_bytes::TryFromSizedBytesError) -> Self { + PakeError::CryptoError(e.into()).into() + } +} + pub(crate) mod utils { use super::*; diff --git a/src/group.rs b/src/group.rs index de3e4d7..a04e812 100644 --- a/src/group.rs +++ b/src/group.rs @@ -17,6 +17,7 @@ use generic_array::{ typenum::{U32, U64}, ArrayLength, GenericArray, }; + use rand_core::{CryptoRng, RngCore}; use std::ops::Mul; use zeroize::Zeroize; diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 3ab08b5..5194596 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -8,7 +8,7 @@ use crate::{ errors::{utils::check_slice_size, InternalPakeError, PakeError, ProtocolError}, hash::Hash, key_exchange::traits::{KeyExchange, ToBytes}, - keypair::{KeyPair, SizedBytes}, + keypair::{KeyPair, SizedBytesExt}, serialization::serialize, }; use digest::{Digest, FixedOutput}; @@ -16,6 +16,7 @@ use generic_array::{ typenum::{Unsigned, U32}, ArrayLength, GenericArray, }; +use generic_bytes::SizedBytes; use hkdf::Hkdf; use hmac::{Hmac, Mac, NewMac}; use rand_core::{CryptoRng, RngCore}; diff --git a/src/keypair.rs b/src/keypair.rs index 0c6bd8b..711175b 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -5,12 +5,10 @@ //! Contains the keypair types that must be supplied for the OPAQUE API -use crate::errors::{utils::check_slice_size, InternalPakeError}; -use generic_array::{ - sequence::Concat, - typenum::{Sum, Unsigned, U32}, - ArrayLength, GenericArray, -}; +use crate::errors::InternalPakeError; +use generic_array::{typenum::U32, GenericArray}; +use generic_bytes::{SizedBytes, TryFromSizedBytesError}; +use generic_bytes_derive::{SizedBytes, TryFromForSizedBytes}; #[cfg(test)] use proptest::prelude::*; #[cfg(test)] @@ -20,25 +18,18 @@ use std::convert::TryInto; use std::fmt::Debug; use x25519_dalek::{PublicKey, StaticSecret}; -use std::convert::TryFrom; +use std::ops::Deref; -use std::ops::{Add, Deref}; - -/// A trait for sized key material that can be represented within a fixed byte -/// array size, used to represent our DH key types -pub trait SizedBytes: Sized + PartialEq { - /// The typed representation of the byte length - type Len: ArrayLength; - - /// Converts this sized key material to a `GenericArray` of the same - /// size. One can convert this to a `&[u8]` with `GenericArray::as_slice()` - /// but the size information is then lost from the type. - fn to_arr(&self) -> GenericArray; - - /// How to parse such sized material from a byte slice. - fn from_bytes(key_bytes: &[u8]) -> Result; +// Pub(crate) convenience extension trait of SizedBytes for our purposes +pub(crate) trait SizedBytesExt: SizedBytes { + fn from_bytes(bytes: &[u8]) -> Result { + ::from_arr(GenericArray::from_slice(bytes)) + } } +// blanket implementation +impl SizedBytesExt for T where T: SizedBytes {} + /// A Keypair trait with public-private verification pub trait KeyPair: Sized { /// The single key representation must have a specific byte size itself @@ -92,62 +83,9 @@ trait KeyPairExt: KeyPair + Debug { #[cfg(test)] impl KeyPairExt for KP where KP: KeyPair + Debug {} -/// This assumes you have defined a SizedBytes instance for a `T`, and defines: -/// - an `impl TryFrom<&[u8b], Error = InternalPakeError>` for a non-generic `T` -/// - an `fn to_bytes(&self) -> Vec` in an `impl T` block -/// -/// Because SizedBytes has a strong notion of size, and TryFrom/to_bytes does -/// not, it's better to use this macro than the one above, where possible. -macro_rules! try_from_and_to_bytes_using_sized_bytes { - ($sized_type: ident) => { - impl TryFrom<&[u8]> for $sized_type { - type Error = InternalPakeError; - - fn try_from(bytes: &[u8]) -> Result { - <$sized_type as SizedBytes>::from_bytes(bytes) - } - } - - #[allow(dead_code)] - impl $sized_type { - fn to_bytes(&self) -> Vec { - self.to_arr().to_vec() - } - } - }; -} - -/// This is a blanket implementation of SizedBytes for any instance of KeyPair -/// with any length of keys. This encodes that we serialize the public key -/// first, followed by the private key in binary formats (and expect it in this -/// order upon decoding). -impl SizedBytes for KP -where - T: SizedBytes + Clone, - KP: KeyPair + PartialEq, - T::Len: Add, - Sum: ArrayLength, -{ - type Len = Sum; - - fn to_arr(&self) -> GenericArray { - let private = self.private().to_arr(); - let public = self.public().to_arr(); - public.concat(private) - } - - fn from_bytes(key_bytes: &[u8]) -> Result { - let checked_bytes = - check_slice_size(key_bytes, ::to_usize(), "key_bytes")?; - let single_key_len = <::Len as Unsigned>::to_usize(); - let public = ::from_bytes(&checked_bytes[..single_key_len])?; - let private = ::from_bytes(&checked_bytes[single_key_len..])?; - KP::new(public, private) - } -} - /// A minimalist key type built around [u8;32] -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, TryFromForSizedBytes)] +#[ErrorType = "::generic_bytes::TryFromSizedBytesError"] #[repr(transparent)] pub struct Key(Vec); @@ -166,17 +104,14 @@ impl SizedBytes for Key { GenericArray::clone_from_slice(&self.0[..]) } - fn from_bytes(key_bytes: &[u8]) -> Result { - let checked_bytes = - check_slice_size(key_bytes, ::to_usize(), "key_bytes")?; - Ok(Key(checked_bytes.to_vec())) + fn from_arr(key_bytes: &GenericArray) -> Result { + Ok(Key(key_bytes.to_vec())) } } -try_from_and_to_bytes_using_sized_bytes!(Key); - /// A representation of an X25519 keypair according to RFC7748 -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, SizedBytes, TryFromForSizedBytes)] +#[ErrorType = "::generic_bytes::TryFromSizedBytesError"] pub struct X25519KeyPair { pk: Key, sk: Key, diff --git a/src/lib.rs b/src/lib.rs index 87cdba5..7505315 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,7 +40,7 @@ //! ## Setup //! To setup the protocol, the server begins by generating a static keypair: //! ``` -//! # use opaque_ke::keypair::{KeyPair, X25519KeyPair, SizedBytes}; +//! # use opaque_ke::keypair::{KeyPair, X25519KeyPair}; //! # use opaque_ke::errors::ProtocolError; //! # use opaque_ke::ciphersuite::CipherSuite; //! # struct Default; @@ -72,7 +72,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::ServerRegistration, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -102,7 +102,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::ClientRegistration, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -135,7 +135,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -169,7 +169,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -211,7 +211,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration, ServerLogin, LoginThirdMessage}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -241,7 +241,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, LoginThirdMessage}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -285,7 +285,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; @@ -340,7 +340,7 @@ //! # use opaque_ke::{ //! # errors::ProtocolError, //! # opaque::{ClientRegistration, ServerRegistration, ClientLogin, ServerLogin, LoginThirdMessage}, -//! # keypair::{KeyPair, X25519KeyPair, SizedBytes}, +//! # keypair::{KeyPair, X25519KeyPair}, //! # slow_hash::NoOpHash, //! # }; //! # use opaque_ke::ciphersuite::CipherSuite; diff --git a/src/opaque.rs b/src/opaque.rs index d016d1f..676ef94 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -15,7 +15,7 @@ use crate::{ group::Group, hash::Hash, key_exchange::traits::{KeyExchange, ToBytes}, - keypair::{KeyPair, SizedBytes}, + keypair::{KeyPair, SizedBytesExt}, oprf, serialization::{ serialize, tokenize, u8_to_credential_type, CredentialType, ProtocolMessageType, @@ -23,6 +23,7 @@ use crate::{ slow_hash::SlowHash, }; use generic_array::{typenum::Unsigned, GenericArray}; +use generic_bytes::SizedBytes; use rand_core::{CryptoRng, RngCore}; use std::collections::HashMap; use std::{convert::TryFrom, marker::PhantomData}; @@ -640,7 +641,7 @@ impl ClientRegistration { /// # Example /// /// ``` - /// use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::{X25519KeyPair, SizedBytes}}; + /// use opaque_ke::{opaque::{ClientRegistration, ServerRegistration}, keypair::X25519KeyPair}; /// # use opaque_ke::errors::ProtocolError; /// # use opaque_ke::keypair::KeyPair; /// use rand_core::{OsRng, RngCore}; @@ -822,7 +823,7 @@ where /// # Example /// /// ``` - /// use opaque_ke::{opaque::*, keypair::{X25519KeyPair, SizedBytes}}; + /// use opaque_ke::{opaque::*, keypair::X25519KeyPair}; /// # use opaque_ke::errors::ProtocolError; /// use rand_core::{OsRng, RngCore}; /// use opaque_ke::ciphersuite::CipherSuite; @@ -898,7 +899,7 @@ where /// # Example /// /// ``` - /// use opaque_ke::{opaque::*, keypair::{KeyPair, X25519KeyPair, SizedBytes}}; + /// use opaque_ke::{opaque::*, keypair::{KeyPair, X25519KeyPair}}; /// # use opaque_ke::errors::ProtocolError; /// use rand_core::{OsRng, RngCore}; /// use opaque_ke::ciphersuite::CipherSuite; diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs index 66e5aad..4015014 100644 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -11,12 +11,13 @@ use crate::{ traits::{KeyExchange, ToBytes}, tripledh::{TripleDH, NONCE_LEN}, }, - keypair::{KeyPair, SizedBytes, X25519KeyPair}, + keypair::{KeyPair, X25519KeyPair}, opaque::*, serialization::{serialize, ProtocolMessageType}, }; use curve25519_dalek::ristretto::RistrettoPoint; +use generic_bytes::SizedBytes; use proptest::{collection::vec, prelude::*}; use rand_core::{OsRng, RngCore}; diff --git a/src/tests/opaque_ke_test.rs b/src/tests/opaque_ke_test.rs index 848afb0..b4f5b36 100644 --- a/src/tests/opaque_ke_test.rs +++ b/src/tests/opaque_ke_test.rs @@ -8,13 +8,14 @@ use crate::{ errors::*, group::Group, key_exchange::tripledh::{TripleDH, NONCE_LEN}, - keypair::{Key, KeyPair, SizedBytes, X25519KeyPair}, + keypair::{Key, KeyPair, X25519KeyPair}, opaque::*, slow_hash::NoOpHash, tests::mock_rng::CycleRng, }; use curve25519_dalek::edwards::EdwardsPoint; use generic_array::GenericArray; +use generic_bytes::SizedBytes; use rand_core::{OsRng, RngCore}; use serde_json::Value; use std::convert::TryFrom;