From e5448fb09c3bd7bb2d60d9aa61cc5690d88c4cc1 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Fri, 2 Sep 2022 10:16:59 +0200 Subject: [PATCH 01/18] Add Hash as `SymKey` super trait. --- CHANGELOG.md | 9 +++++++++ Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- src/symmetric_crypto/key.rs | 4 ++-- src/symmetric_crypto/mod.rs | 3 ++- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9acac50..266e49d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. +--- +## [2.0.1] - 2022-09-02 +### Added +- `Hash` super trait to `SymKey` +### Changed +### Fixed +### Removed +--- + --- ## [2.0.0] - 2022-08-22 ### Added diff --git a/Cargo.lock b/Cargo.lock index 0dbdc4e..181aa84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,7 +102,7 @@ dependencies = [ [[package]] name = "cosmian_crypto_core" -version = "2.0.0" +version = "2.0.1" dependencies = [ "aes 0.8.1", "aes-gcm", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1079fb8528d9f9c888b1e8aa651e6e079ade467323d58f75faf1d30b1808f540" +checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" dependencies = [ "libc", ] @@ -434,9 +434,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" dependencies = [ "cfg-if", "cpufeatures", @@ -462,18 +462,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 31f20d7..8bb36f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Crypto lib for pure crypto primitives" edition = "2021" license = "MIT/Apache-2.0" name = "cosmian_crypto_core" -version = "2.0.0" +version = "2.0.1" [lib] crate-type = ["cdylib", "rlib"] diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index 8ef84e0..9da46a1 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -4,7 +4,7 @@ use crate::{symmetric_crypto::SymKey, CryptoCoreError, KeyTrait}; use aes::cipher::generic_array::{ArrayLength, GenericArray}; use rand_core::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; -use std::{convert::TryFrom, fmt::Display, ops::Deref}; +use std::{convert::TryFrom, fmt::Display, hash::Hash, ops::Deref}; use zeroize::{Zeroize, ZeroizeOnDrop}; /// Symmetric key of a given size. @@ -36,7 +36,7 @@ impl> KeyTrait for Key { } } -impl> SymKey for Key { +impl> SymKey for Key { /// Convert the given key into a byte slice, without copy. fn as_bytes(&self) -> &[u8] { &self.0 diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 9833e48..0830729 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -17,10 +17,11 @@ use crate::{CryptoCoreError, KeyTrait}; use generic_array::GenericArray; use nonce::NonceTrait; use rand_core::{CryptoRng, RngCore}; +use std::hash::Hash; use std::vec::Vec; /// Defines a symmetric encryption key. -pub trait SymKey: KeyTrait { +pub trait SymKey: KeyTrait + Hash { /// Convert the given key into a byte slice. fn as_bytes(&self) -> &[u8]; From 52f714ebdd150207e2b31f441ca086a22950abfc Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Fri, 2 Sep 2022 16:11:37 +0200 Subject: [PATCH 02/18] Use constant generics --- CHANGELOG.md | 4 +- Cargo.lock | 8 +- Cargo.toml | 3 +- src/asymmetric_crypto.rs | 64 +++++++------- src/entropy.rs | 12 ++- src/kdf.rs | 11 ++- src/lib.rs | 11 +-- src/symmetric_crypto/aes_256_gcm_pure/dem.rs | 26 +++--- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 32 +++---- src/symmetric_crypto/block.rs | 52 +++++------ src/symmetric_crypto/key.rs | 92 ++++++++++---------- src/symmetric_crypto/mod.rs | 12 +-- 12 files changed, 160 insertions(+), 167 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 266e49d..c0e3709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,10 @@ All notable changes to this project will be documented in this file. --- -## [2.0.1] - 2022-09-02 +## [3.0.0] - 2022-09-02 ### Added -- `Hash` super trait to `SymKey` ### Changed +- use constant generics ### Fixed ### Removed --- diff --git a/Cargo.lock b/Cargo.lock index 181aa84..6e6ef68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,12 +102,11 @@ dependencies = [ [[package]] name = "cosmian_crypto_core" -version = "2.0.1" +version = "3.0.0" dependencies = [ "aes 0.8.1", "aes-gcm", "curve25519-dalek", - "generic-array", "getrandom 0.2.7", "hex", "hkdf", @@ -188,7 +187,6 @@ version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ - "serde", "typenum", "version_check", ] @@ -318,9 +316,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "opaque-debug" diff --git a/Cargo.toml b/Cargo.toml index 8bb36f0..4424ac8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Crypto lib for pure crypto primitives" edition = "2021" license = "MIT/Apache-2.0" name = "cosmian_crypto_core" -version = "2.0.1" +version = "3.0.0" [lib] crate-type = ["cdylib", "rlib"] @@ -15,7 +15,6 @@ path = "src/lib.rs" aes = "0.8" aes-gcm = "0.9" curve25519-dalek = "3.2" -generic-array = { version = "0.14.5", features = ["serde"] } # specify the js feature for the WASM target getrandom = { version = "0.2", features = ["js"] } hex = "0.4" diff --git a/src/asymmetric_crypto.rs b/src/asymmetric_crypto.rs index 32c03b0..85fe17e 100644 --- a/src/asymmetric_crypto.rs +++ b/src/asymmetric_crypto.rs @@ -11,7 +11,6 @@ use curve25519_dalek::{ ristretto::{CompressedRistretto, RistrettoPoint}, scalar::Scalar, }; -use generic_array::{typenum::U32, GenericArray}; use rand_core::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use std::{ @@ -21,6 +20,12 @@ use std::{ }; use zeroize::{Zeroize, ZeroizeOnDrop}; +/// X25519 secret key length +pub const X25519_SK_LENGTH: usize = 32; + +/// X25519 public key length +pub const X25519_PK_LENGTH: usize = 32; + /// Asymmetric private key based on Curve25519. /// /// Internally, a curve scalar is used. It is 128-bits long. @@ -52,25 +57,22 @@ impl X25519PrivateKey { } } -impl KeyTrait for X25519PrivateKey { - type Length = U32; - - /// Convert the given private key into bytes. - #[inline] - #[must_use] - fn to_bytes(&self) -> GenericArray { - GenericArray::::from(self.0.to_bytes()) +impl KeyTrait for X25519PrivateKey { + /// Converts the given key into bytes. + fn to_bytes(&self) -> [u8; Self::LENGTH] { + self.0.to_bytes() } + /// Converts the given bytes into key. fn try_from_bytes(bytes: &[u8]) -> Result { Self::try_from(bytes) } } -impl TryFrom<[u8; 32]> for X25519PrivateKey { +impl TryFrom<[u8; Self::LENGTH]> for X25519PrivateKey { type Error = CryptoCoreError; - fn try_from(bytes: [u8; 32]) -> Result { + fn try_from(bytes: [u8; Self::LENGTH]) -> Result { let scalar = Scalar::from_canonical_bytes(bytes).ok_or_else(|| { Self::Error::ConversionError( "Given bytes do not represent a canonical Scalar!".to_string(), @@ -84,7 +86,7 @@ impl TryFrom<&[u8]> for X25519PrivateKey { type Error = CryptoCoreError; fn try_from(bytes: &[u8]) -> Result { - let bytes: [u8; 32] = bytes.try_into().map_err(|e| { + let bytes: [u8; Self::LENGTH] = bytes.try_into().map_err(|e| { Self::Error::ConversionError(format!( "Error while converting slice of size {} to `X25519PublicKey`: {}", bytes.len(), @@ -95,15 +97,9 @@ impl TryFrom<&[u8]> for X25519PrivateKey { } } -impl From<&X25519PrivateKey> for [u8; 32] { - fn from(key: &X25519PrivateKey) -> Self { - key.0.to_bytes() - } -} - // Needed by serde to derive `Deserialize`. Do not use otherwise since there // is a copy anyway -impl From for [u8; 32] { +impl From for [u8; X25519_SK_LENGTH] { fn from(key: X25519PrivateKey) -> Self { key.0.to_bytes() } @@ -240,14 +236,11 @@ impl X25519PublicKey { } } -impl KeyTrait for X25519PublicKey { - type Length = U32; - - /// Convert the given public key into an array of bytes. +impl KeyTrait for X25519PublicKey { + /// Converts the given public key into an array of bytes. #[inline] - #[must_use] - fn to_bytes(&self) -> GenericArray { - GenericArray::::from(self.0.compress().to_bytes()) + fn to_bytes(&self) -> [u8; Self::LENGTH] { + self.0.compress().to_bytes() } fn try_from_bytes(bytes: &[u8]) -> Result { @@ -261,10 +254,10 @@ impl From<&X25519PrivateKey> for X25519PublicKey { } } -impl TryFrom<[u8; 32]> for X25519PublicKey { +impl TryFrom<[u8; Self::LENGTH]> for X25519PublicKey { type Error = CryptoCoreError; - fn try_from(bytes: [u8; 32]) -> Result { + fn try_from(bytes: [u8; Self::LENGTH]) -> Result { Ok(Self(CompressedRistretto(bytes).decompress().ok_or_else( || { CryptoCoreError::ConversionError( @@ -279,7 +272,7 @@ impl TryFrom<&[u8]> for X25519PublicKey { type Error = CryptoCoreError; fn try_from(bytes: &[u8]) -> Result { - let bytes: [u8; 32] = bytes.try_into().map_err(|e| { + let bytes: [u8; Self::LENGTH] = bytes.try_into().map_err(|e| { Self::Error::ConversionError(format!( "Error while converting slice of size {} to `X25519PublicKey`: {}", bytes.len(), @@ -292,13 +285,13 @@ impl TryFrom<&[u8]> for X25519PublicKey { // Needed by serde to derive `Deserialize`. Do not use otherwise since there // is a copy anyway. -impl From for [u8; 32] { +impl From for [u8; X25519_PK_LENGTH] { fn from(key: X25519PublicKey) -> Self { key.0.compress().to_bytes() } } -impl From<&X25519PublicKey> for [u8; 32] { +impl From<&X25519PublicKey> for [u8; X25519_PK_LENGTH] { fn from(key: &X25519PublicKey) -> Self { key.0.compress().to_bytes() } @@ -379,15 +372,18 @@ impl ZeroizeOnDrop for X25519PublicKey {} #[cfg(test)] mod test { use crate::{ - asymmetric_crypto::{X25519PrivateKey, X25519PublicKey}, + asymmetric_crypto::{ + X25519PrivateKey, X25519PublicKey, X25519_PK_LENGTH, X25519_SK_LENGTH, + }, entropy::CsRng, + KeyTrait, }; #[test] fn test_private_key_serialization() { let mut rng = CsRng::new(); let sk = X25519PrivateKey::new(&mut rng); - let bytes: [u8; 32] = (&sk).into(); + let bytes: [u8; X25519_SK_LENGTH] = sk.to_bytes(); let recovered = X25519PrivateKey::try_from(bytes).unwrap(); assert_eq!(sk, recovered); } @@ -396,7 +392,7 @@ mod test { fn test_public_key_serialization() { let mut rng = CsRng::new(); let pk = X25519PublicKey::new(&mut rng); - let bytes: [u8; 32] = (&pk).into(); + let bytes: [u8; X25519_PK_LENGTH] = pk.to_bytes(); let recovered = super::X25519PublicKey::try_from(bytes).unwrap(); assert_eq!(pk, recovered); } diff --git a/src/entropy.rs b/src/entropy.rs index 4719618..88fc050 100644 --- a/src/entropy.rs +++ b/src/entropy.rs @@ -1,4 +1,3 @@ -use generic_array::{ArrayLength, GenericArray}; use rand_core::{CryptoRng, RngCore, SeedableRng}; use rand_hc::Hc128Rng; @@ -21,8 +20,8 @@ impl CsRng { /// Generate a vector of random bytes with the given length. /// /// - `len` : number of random bytes to generate - pub fn generate_random_bytes>(&mut self) -> GenericArray { - let mut bytes = GenericArray::::default(); + pub fn generate_random_bytes(&mut self) -> [u8; LENGTH] { + let mut bytes = [0; LENGTH]; self.rng.fill_bytes(&mut bytes); bytes } @@ -58,16 +57,15 @@ impl CryptoRng for CsRng {} mod test { use crate::entropy::CsRng; - use generic_array::typenum::{Unsigned, U1024}; #[test] fn test_random_bytes() { let mut cs_rng = CsRng::default(); - type N = U1024; + const N: usize = 1024; let random_bytes_1 = cs_rng.generate_random_bytes::(); - assert_eq!(::to_usize(), random_bytes_1.len()); + assert_eq!(N, random_bytes_1.len()); let random_bytes_2 = cs_rng.generate_random_bytes(); - assert_eq!(::to_usize(), random_bytes_1.len()); + assert_eq!(N, random_bytes_1.len()); assert_ne!(random_bytes_1, random_bytes_2); } } diff --git a/src/kdf.rs b/src/kdf.rs index 577c2f8..a9b02b1 100644 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -1,5 +1,4 @@ use crate::CryptoCoreError; -use generic_array::{ArrayLength, GenericArray}; use hkdf::Hkdf; use sha2::Sha256; @@ -9,18 +8,18 @@ use sha2::Sha256; /// /// - `bytes` : input bytes to hash, should be at least 32-bytes long /// - `info` : some optional additional information to use in the hash -pub fn hkdf_256>( +pub fn hkdf_256( bytes: &[u8], info: &[u8], -) -> Result, CryptoCoreError> { +) -> Result<[u8; LENGTH], CryptoCoreError> { if bytes.len() < 32 { return Err(CryptoCoreError::InvalidSize( - "Input `bytes` size should be at least 32".to_string(), + "Input `bytes` size should be at least 32 bytes".to_string(), )); } let h = Hkdf::::new(None, bytes); - let mut out = GenericArray::::default(); + let mut out = [0; LENGTH]; h.expand(info, &mut out) - .map_err(|_| CryptoCoreError::KdfError(KeyLength::to_usize()))?; + .map_err(|_| CryptoCoreError::KdfError(LENGTH))?; Ok(out) } diff --git a/src/lib.rs b/src/lib.rs index 85a612f..8e682aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,19 +23,20 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub use crate::error::CryptoCoreError; pub mod reexport { - pub use generic_array; // reexport `rand_core` so that the PRNG implement the correct version of the traits pub use rand_core; } /// Trait defining a cryptographic key. -pub trait KeyTrait: PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop { - /// Number of bytes in the serialized key. - type Length: Eq + generic_array::ArrayLength; +pub trait KeyTrait: + PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop +{ + /// Key length + const LENGTH: usize = LENGTH; /// Convert the given key into a vector of bytes. #[must_use] - fn to_bytes(&self) -> generic_array::GenericArray; + fn to_bytes(&self) -> [u8; LENGTH]; /// Convert the given bytes into a key. An error is returned in case the /// conversion fails. diff --git a/src/symmetric_crypto/aes_256_gcm_pure/dem.rs b/src/symmetric_crypto/aes_256_gcm_pure/dem.rs index 519850b..647e466 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/dem.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/dem.rs @@ -2,31 +2,31 @@ use crate::{ symmetric_crypto::{ - aes_256_gcm_pure::Aes256GcmCrypto, nonce::NonceTrait, Dem, SymmetricCrypto, + aes_256_gcm_pure::{Aes256GcmCrypto, KEY_LENGTH}, + nonce::NonceTrait, + Dem, SymmetricCrypto, }, - CryptoCoreError, KeyTrait, + CryptoCoreError, }; -use generic_array::typenum::Unsigned; use rand_core::{CryptoRng, RngCore}; use std::convert::TryFrom; -impl Dem for Aes256GcmCrypto { +impl Dem for Aes256GcmCrypto { fn encaps( rng: &mut R, secret_key: &[u8], additional_data: Option<&[u8]>, message: &[u8], ) -> Result, CryptoCoreError> { - let key_length = <::Length as Unsigned>::to_usize(); - if secret_key.len() < key_length { + if secret_key.len() < KEY_LENGTH { return Err(CryptoCoreError::SizeError { given: secret_key.len(), - expected: key_length, + expected: KEY_LENGTH, }); } // AES GCM includes an authentication method // there is no need for parsing a MAC key - let key = Self::Key::try_from(&secret_key[..key_length])?; + let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?; let nonce = Self::Nonce::new(rng); let mut c = Self::encrypt(&key, message, &nonce, additional_data) .map_err(|err| CryptoCoreError::EncryptionError(err.to_string()))?; @@ -42,16 +42,15 @@ impl Dem for Aes256GcmCrypto { additional_data: Option<&[u8]>, encapsulation: &[u8], ) -> Result, CryptoCoreError> { - let key_length = <::Length as Unsigned>::to_usize(); - if secret_key.len() < key_length { + if secret_key.len() < KEY_LENGTH { return Err(CryptoCoreError::SizeError { given: secret_key.len(), - expected: key_length, + expected: KEY_LENGTH, }); } // AES GCM includes an authentication method // there is no need for parsing a MAC key - let key = Self::Key::try_from(&secret_key[..key_length])?; + let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?; let nonce = Self::Nonce::try_from(&encapsulation[..Self::Nonce::LENGTH])?; Self::decrypt( &key, @@ -71,14 +70,13 @@ mod tests { symmetric_crypto::{aes_256_gcm_pure::Aes256GcmCrypto, Dem}, CryptoCoreError, }; - use generic_array::typenum::U256; #[test] fn test_dem() -> Result<(), CryptoCoreError> { let m = b"my secret message"; let additional_data = Some(b"public tag".as_slice()); let mut rng = CsRng::new(); - let secret_key = rng.generate_random_bytes::(); + let secret_key = rng.generate_random_bytes::<256>(); let c = Aes256GcmCrypto::encaps(&mut rng, &secret_key, additional_data, m)?; let res = Aes256GcmCrypto::decaps(&secret_key, additional_data, &c)?; if res != m { diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index d0a4a0f..0505072 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -6,18 +6,19 @@ use crate::{ symmetric_crypto::{nonce::NonceTrait, SymmetricCrypto}, CryptoCoreError, }; -use aes::cipher::Unsigned; use aes_gcm::{ aead::{Aead, NewAead, Payload}, + aes::cipher::generic_array::GenericArray, AeadInPlace, Aes256Gcm, }; -use generic_array::{typenum, GenericArray}; use std::fmt::Display; +use super::SymKey; + pub mod dem; /// Use a 256-bit AES key -pub type KeyLength = typenum::U32; +pub const KEY_LENGTH: usize = 32; /// Use a 96-bit nonce pub const NONCE_LENGTH: usize = 12; @@ -25,7 +26,7 @@ pub const NONCE_LENGTH: usize = 12; /// Use a 128-bit MAC tag pub const MAC_LENGTH: usize = 16; -pub type Key = crate::symmetric_crypto::key::Key; +pub type Key = crate::symmetric_crypto::key::Key; pub type Nonce = crate::symmetric_crypto::nonce::Nonce; @@ -39,7 +40,7 @@ impl Display for Aes256GcmCrypto { } } -impl SymmetricCrypto for Aes256GcmCrypto { +impl SymmetricCrypto for Aes256GcmCrypto { type Key = Key; type Nonce = Nonce; @@ -48,7 +49,7 @@ impl SymmetricCrypto for Aes256GcmCrypto { fn description() -> String { format!( "AES 256 GCM pure Rust (key bits: {}, nonce bits: {}, tag bits: {})", - KeyLength::to_usize() * 8, + KEY_LENGTH * 8, NONCE_LENGTH * 8, MAC_LENGTH * 8 ) @@ -86,7 +87,7 @@ pub fn encrypt_combined( ) -> Result, CryptoCoreError> { let payload = additional_data.map_or_else(|| Payload::from(bytes), |aad| Payload { msg: bytes, aad }); - Aes256Gcm::new(key) + Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) .encrypt(GenericArray::from_slice(nonce.as_slice()), payload) .map_err(|e| CryptoCoreError::EncryptionError(e.to_string())) } @@ -102,7 +103,7 @@ pub fn encrypt_in_place_detached( nonce: &Nonce, additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { - Aes256Gcm::new(key) + Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) .encrypt_in_place_detached( GenericArray::from_slice(nonce.as_slice()), additional_data.unwrap_or_default(), @@ -125,7 +126,7 @@ pub fn decrypt_combined( additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { let payload = additional_data.map_or_else(|| Payload::from(msg), |aad| Payload { msg, aad }); - Aes256Gcm::new(key) + Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) .decrypt(GenericArray::from_slice(nonce.as_slice()), payload) .map_err(|e| CryptoCoreError::DecryptionError(e.to_string())) } @@ -144,7 +145,7 @@ pub fn decrypt_in_place_detached( nonce: &Nonce, additional_data: Option<&[u8]>, ) -> Result<(), CryptoCoreError> { - Aes256Gcm::new(key) + Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) .decrypt_in_place_detached( GenericArray::from_slice(nonce.as_slice()), additional_data.unwrap_or_default(), @@ -168,13 +169,12 @@ mod tests { }, CryptoCoreError, }; - use generic_array::typenum::{U42, U8192}; #[test] fn test_encryption_decryption_combined() -> Result<(), CryptoCoreError> { let mut cs_rng = CsRng::new(); let key = Key::new(&mut cs_rng); - let bytes = cs_rng.generate_random_bytes::(); + let bytes = cs_rng.generate_random_bytes::<8192>(); let iv = Nonce::new(&mut cs_rng); // no additional data let encrypted_result = encrypt_combined(&key, &bytes, &iv, None)?; @@ -183,14 +183,14 @@ mod tests { let recovered = decrypt_combined(&key, &encrypted_result, &iv, None)?; assert_eq!(bytes.to_vec(), recovered); // additional data - let aad = cs_rng.generate_random_bytes::(); + let aad = cs_rng.generate_random_bytes::<42>(); let encrypted_result = encrypt_combined(&key, &bytes, &iv, Some(&aad))?; assert_ne!(encrypted_result, bytes.to_vec()); assert_eq!(bytes.len() + MAC_LENGTH, encrypted_result.len()); let recovered = decrypt_combined(&key, &encrypted_result, &iv, Some(&aad))?; assert_eq!(bytes.to_vec(), recovered); // data should not be recovered if the AAD is modified - let aad = cs_rng.generate_random_bytes::(); + let aad = cs_rng.generate_random_bytes::<42>(); let recovered = decrypt_combined(&key, &encrypted_result, &iv, Some(&aad)); assert_ne!(Ok(bytes.to_vec()), recovered); // data should not be recovered if the key is modified @@ -204,7 +204,7 @@ mod tests { fn test_encryption_decryption_detached() -> Result<(), CryptoCoreError> { let mut cs_rng = CsRng::new(); let key = Key::new(&mut cs_rng); - let bytes = cs_rng.generate_random_bytes::(); + let bytes = cs_rng.generate_random_bytes::<8192>(); let iv = Nonce::new(&mut cs_rng); // no additional data let mut data = bytes; @@ -215,7 +215,7 @@ mod tests { decrypt_in_place_detached(&key, &mut data, &tag, &iv, None)?; assert_eq!(bytes, data); // // additional data - let ad = cs_rng.generate_random_bytes::(); + let ad = cs_rng.generate_random_bytes::<42>(); let mut data = bytes; let tag = encrypt_in_place_detached(&key, &mut data, &iv, Some(&ad))?; assert_ne!(bytes, data); diff --git a/src/symmetric_crypto/block.rs b/src/symmetric_crypto/block.rs index bfb43f5..907a6bb 100644 --- a/src/symmetric_crypto/block.rs +++ b/src/symmetric_crypto/block.rs @@ -13,21 +13,22 @@ use rand_core::{CryptoRng, RngCore}; /// is made of a `BlockHeader` containing the nonce, the cipher text and - /// depending on the symmetric scheme - an authentication MAC. The nonce is /// refreshed on each call to `to_encrypted_bytes(...)` -pub struct Block +pub struct Block where - S: SymmetricCrypto, + S: SymmetricCrypto, { clear_text: Vec, //padded with zeroes if need be phantom_data: std::marker::PhantomData, } -impl Block +impl + Block where - S: SymmetricCrypto, + S: SymmetricCrypto, { /// Number of bytes added to the size of the input data in the output ciphertext. pub const ENCRYPTION_OVERHEAD: usize = - BlockHeader::::LENGTH + ::MAC_LENGTH; + BlockHeader::::LENGTH + >::MAC_LENGTH; /// Maximum number of bytes for an output ciphertext. pub const MAX_ENCRYPTED_LENGTH: usize = MAX_CLEAR_TEXT_LENGTH + Self::ENCRYPTION_OVERHEAD; @@ -47,7 +48,7 @@ where /// same values used to encrypt the block pub fn from_encrypted_bytes( encrypted_bytes: &[u8], - symmetric_key: &::Key, + symmetric_key: &>::Key, uid: &[u8], block_number: usize, ) -> Result { @@ -64,9 +65,10 @@ where encrypted_bytes.len(), ))); } - let block_header_len = BlockHeader::::LENGTH; + let block_header_len = BlockHeader::::LENGTH; // recover the block header and regenerate the IV - let block_header = BlockHeader::::parse(&encrypted_bytes[0..block_header_len])?; + let block_header = + BlockHeader::::parse(&encrypted_bytes[0..block_header_len])?; let mut ad = uid.to_vec(); // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. // The `u64`-cast prevents build on those 32-bits machine or on @@ -92,7 +94,7 @@ where pub fn to_encrypted_bytes( &self, rng: &mut R, - symmetric_key: &::Key, + symmetric_key: &>::Key, uid: &[u8], block_number: usize, ) -> Result, CryptoCoreError> { @@ -113,7 +115,7 @@ where ); // write the header bytes.append( - &mut BlockHeader:: { + &mut BlockHeader:: { nonce: nonce.clone(), } .to_bytes(), @@ -170,9 +172,9 @@ where } } -impl Default for Block +impl Default for Block where - S: SymmetricCrypto, + S: SymmetricCrypto, { fn default() -> Self { Self::new() @@ -180,23 +182,23 @@ where } /// The `BlockHeader` contains the nonce/IV of an encrypted `Block` -pub struct BlockHeader +pub struct BlockHeader where - S: SymmetricCrypto, + S: SymmetricCrypto, { - nonce: ::Nonce, + nonce: >::Nonce, } -impl BlockHeader +impl BlockHeader where - S: SymmetricCrypto, + S: SymmetricCrypto, { - pub const LENGTH: usize = ::Nonce::LENGTH; + pub const LENGTH: usize = >::Nonce::LENGTH; pub fn parse(bytes: &[u8]) -> Result { //TODO: use transmute to make this faster ? Ok(Self { - nonce: <::Nonce>::try_from_bytes(bytes)?, + nonce: <>::Nonce>::try_from_bytes(bytes)?, }) } @@ -217,12 +219,10 @@ mod tests { use super::Block; use crate::{ entropy::CsRng, - symmetric_crypto::aes_256_gcm_pure::{Aes256GcmCrypto, Key}, + symmetric_crypto::aes_256_gcm_pure::{Aes256GcmCrypto, Key, KEY_LENGTH}, }; - use generic_array::typenum::{U100, U16384}; - const MAX_CLEAR_TEXT_LENGTH: usize = 4096; - type Bl = Block; + type Bl = Block; #[test] fn test_empty_block() { @@ -250,7 +250,7 @@ mod tests { let mut b = Bl::new(); assert!(b.clear_text().is_empty()); - let data = cs_rng.generate_random_bytes::(); + let data = cs_rng.generate_random_bytes::<16384>(); let written = b.write(0, &data).expect("failed writing data"); assert_eq!(MAX_CLEAR_TEXT_LENGTH, written); @@ -280,11 +280,11 @@ mod tests { let mut b = Bl::new(); assert!(b.clear_text().is_empty()); - let data1 = cs_rng.generate_random_bytes::(); + let data1 = cs_rng.generate_random_bytes::<100>(); let written = b.write(0, &data1).expect("failed writing data"); assert_eq!(100, written); - let data2 = cs_rng.generate_random_bytes::(); + let data2 = cs_rng.generate_random_bytes::<100>(); let written = b.write(200, &data2).expect("failed writing data"); assert_eq!(100, written); diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index 9da46a1..dbd3275 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -1,101 +1,103 @@ //! Define a symmetric key object of variable size. use crate::{symmetric_crypto::SymKey, CryptoCoreError, KeyTrait}; -use aes::cipher::generic_array::{ArrayLength, GenericArray}; use rand_core::{CryptoRng, RngCore}; -use serde::{Deserialize, Serialize}; use std::{convert::TryFrom, fmt::Display, hash::Hash, ops::Deref}; use zeroize::{Zeroize, ZeroizeOnDrop}; /// Symmetric key of a given size. /// /// It is internally built using an array of bytes of the given length. -#[derive(Debug, Default, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct Key>(GenericArray); +#[derive(Debug, Hash, Clone, PartialEq, Eq)] +pub struct Key([u8; LENGTH]); -impl> Key { +impl Key { /// Generate a new symmetric random `Key` pub fn new(rng: &mut R) -> Self { - let mut key = Self(GenericArray::::default()); - rng.fill_bytes(&mut key.0); - key + let mut key = [0; KEY_LENGTH]; + rng.fill_bytes(&mut key); + Self(key) } } -impl> KeyTrait for Key { - type Length = KeyLength; - - /// Convert the given key into bytes, with copy. - fn to_bytes(&self) -> generic_array::GenericArray { - self.0.clone() +impl KeyTrait for Key { + /// Convert the given key into bytes. + #[inline] + fn to_bytes(&self) -> [u8; LENGTH] { + self.0.to_owned() } /// Try to convert the given bytes into a key. Size must be correct. + #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { Self::try_from(bytes) } } -impl> SymKey for Key { - /// Convert the given key into a byte slice, without copy. +impl SymKey for Key { + /// Convert the given key into a byte slice. + #[inline] fn as_bytes(&self) -> &[u8] { &self.0 } - fn from_bytes(bytes: GenericArray) -> Self { + /// Convert the given bytes with correct size into a key. + fn from_bytes(bytes: [u8; KEY_LENGTH]) -> Self { Self(bytes) } } -impl> From> for GenericArray { - fn from(k: Key) -> Self { - k.to_bytes() +impl From> for [u8; KEY_LENGTH] { + fn from(k: Key) -> Self { + k.0 } } -impl> From> for Key { - fn from(b: GenericArray) -> Self { +impl From<[u8; KEY_LENGTH]> for Key { + fn from(b: [u8; KEY_LENGTH]) -> Self { Self(b) } } -impl<'a, KeyLength: ArrayLength> TryFrom<&'a [u8]> for Key { +impl<'a, const KEY_LENGTH: usize> TryFrom<&'a [u8]> for Key { type Error = CryptoCoreError; fn try_from(bytes: &'a [u8]) -> Result { - if bytes.len() != KeyLength::to_usize() { - return Err(Self::Error::SizeError { - given: bytes.len(), - expected: KeyLength::to_usize(), - }); - } - Ok(Self(GenericArray::::clone_from_slice(bytes))) + let bytes = <[u8; KEY_LENGTH]>::try_from(bytes) + .map_err(|e| Self::Error::ConversionError(e.to_string()))?; + Ok(Self(bytes)) } } -impl> Display for Key { +impl Display for Key { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", hex::encode(self.as_slice())) + write!(f, "{}", hex::encode(self.as_bytes())) } } -impl> Zeroize for Key { +impl Default for Key { + fn default() -> Self { + Self([0; KEY_LENGTH]) + } +} + +impl Zeroize for Key { fn zeroize(&mut self) { self.0.zeroize(); } } // Implement `Drop` trait to follow R23. -impl> Drop for Key { +impl Drop for Key { fn drop(&mut self) { self.zeroize(); } } -impl> ZeroizeOnDrop for Key {} +impl ZeroizeOnDrop for Key {} -impl> Deref for Key { - type Target = GenericArray; +impl Deref for Key { + type Target = [u8]; fn deref(&self) -> &Self::Target { &self.0 @@ -105,24 +107,26 @@ impl> Deref for Key { #[cfg(test)] mod tests { - use crate::{entropy::CsRng, symmetric_crypto::key::Key, KeyTrait}; - use generic_array::typenum::{ToInt, U32}; + use crate::{entropy::CsRng, symmetric_crypto::key::Key}; + use std::ops::Deref; + + const KEY_LENGTH: usize = 32; #[test] fn test_key() { let mut cs_rng = CsRng::new(); - let key_1 = Key::::new(&mut cs_rng); - assert_eq!(>::to_int(), key_1.len()); + let key_1 = Key::::new(&mut cs_rng); + assert_eq!(KEY_LENGTH, key_1.len()); let key_2 = Key::new(&mut cs_rng); - assert_eq!(>::to_int(), key_2.len()); + assert_eq!(KEY_LENGTH, key_2.len()); assert_ne!(key_1, key_2); } #[test] fn test_key_serialization() { let mut cs_rng = CsRng::new(); - let key = Key::::new(&mut cs_rng); - let bytes = key.to_bytes(); + let key = Key::<32>::new(&mut cs_rng); + let bytes = <[u8; 32]>::try_from(key.deref()).unwrap(); let res = Key::try_from(bytes).unwrap(); assert_eq!(key, res); } diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 0830729..b874071 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -14,27 +14,27 @@ pub use metadata::BytesScanner; pub use metadata::Metadata; use crate::{CryptoCoreError, KeyTrait}; -use generic_array::GenericArray; use nonce::NonceTrait; use rand_core::{CryptoRng, RngCore}; use std::hash::Hash; use std::vec::Vec; /// Defines a symmetric encryption key. -pub trait SymKey: KeyTrait + Hash { +pub trait SymKey: KeyTrait + Hash { /// Convert the given key into a byte slice. + #[must_use] fn as_bytes(&self) -> &[u8]; /// Convert the given bytes into a key. #[must_use] - fn from_bytes(bytes: GenericArray) -> Self; + fn from_bytes(bytes: [u8; LENGTH]) -> Self; } /// Defines a symmetric encryption scheme. If this scheme is authenticated, /// the `MAC_LENGTH` will be greater than `0`. -pub trait SymmetricCrypto: Send + Sync { +pub trait SymmetricCrypto: Send + Sync { const MAC_LENGTH: usize; - type Key: SymKey; + type Key: SymKey; type Nonce: NonceTrait; /// A short description of the scheme @@ -87,7 +87,7 @@ pub trait SymmetricCrypto: Send + Sync { /// Defines a DEM based on a symmetric scheme as defined in section 9.1 of the /// [ISO 2004](https://www.shoup.net/iso/std6.pdf). -pub trait Dem: SymmetricCrypto { +pub trait Dem: SymmetricCrypto { /// Number of bytes added to the message length in the encapsulation. const ENCAPSULATION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; From 1e4193d005305d08725fa40437a408722005968e Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 5 Sep 2022 11:16:37 +0200 Subject: [PATCH 03/18] Upgrade `aes-gcm` --- Cargo.lock | 78 ++++++++------------ Cargo.toml | 3 +- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 8 +- 3 files changed, 33 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e6ef68..637e02d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,25 +4,14 @@ version = 3 [[package]] name = "aead" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" dependencies = [ + "crypto-common", "generic-array", ] -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "opaque-debug", -] - [[package]] name = "aes" version = "0.8.1" @@ -30,19 +19,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe0133578c0986e1fe3dfcd4af1cc5b2dd6c3dbf534d69916ce16a2701d40ba" dependencies = [ "cfg-if", - "cipher 0.4.3", + "cipher", "cpufeatures", ] [[package]] name = "aes-gcm" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" dependencies = [ "aead", - "aes 0.7.5", - "cipher 0.3.0", + "aes", + "cipher", "ctr", "ghash", "subtle", @@ -56,9 +45,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] @@ -81,15 +70,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.3" @@ -104,7 +84,6 @@ dependencies = [ name = "cosmian_crypto_core" version = "3.0.0" dependencies = [ - "aes 0.8.1", "aes-gcm", "curve25519-dalek", "getrandom 0.2.7", @@ -122,9 +101,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -136,16 +115,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.3", "typenum", ] [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0d14f329cfbaf5d0e06b5e87fff7e265d2673c5ea7d2c27691a2c107db1442a0" dependencies = [ - "cipher 0.3.0", + "cipher", ] [[package]] @@ -217,9 +197,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug", "polyval", @@ -328,9 +308,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" dependencies = [ "cfg-if", "cpufeatures", @@ -432,9 +412,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215" +checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" dependencies = [ "cfg-if", "cpufeatures", @@ -460,18 +440,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" +checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" +checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" dependencies = [ "proc-macro2", "quote", @@ -492,11 +472,11 @@ checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" dependencies = [ - "generic-array", + "crypto-common", "subtle", ] diff --git a/Cargo.toml b/Cargo.toml index 4424ac8..0ad9984 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,7 @@ name = "cosmian_crypto_core" path = "src/lib.rs" [dependencies] -aes = "0.8" -aes-gcm = "0.9" +aes-gcm = "0.10" curve25519-dalek = "3.2" # specify the js feature for the WASM target getrandom = { version = "0.2", features = ["js"] } diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index 0505072..ed96b6b 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -3,18 +3,16 @@ //! //! It will use the AES native interface on the CPU if available. use crate::{ - symmetric_crypto::{nonce::NonceTrait, SymmetricCrypto}, + symmetric_crypto::{nonce::NonceTrait, SymKey, SymmetricCrypto}, CryptoCoreError, }; use aes_gcm::{ - aead::{Aead, NewAead, Payload}, + aead::{Aead, Payload}, aes::cipher::generic_array::GenericArray, - AeadInPlace, Aes256Gcm, + AeadInPlace, Aes256Gcm, KeyInit, }; use std::fmt::Display; -use super::SymKey; - pub mod dem; /// Use a 256-bit AES key From b661055b3c10435165db11f1d95422d04e5a1f65 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 5 Sep 2022 12:06:01 +0200 Subject: [PATCH 04/18] Remove `rand` dependency --- Cargo.lock | 19 ------------------- Cargo.toml | 3 +-- src/symmetric_crypto/block.rs | 3 ++- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 637e02d..e5c68af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,6 @@ dependencies = [ "hex", "hkdf", "num-bigint", - "rand", "rand_core 0.6.3", "rand_hc", "serde", @@ -318,12 +317,6 @@ dependencies = [ "universal-hash", ] -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - [[package]] name = "proc-macro2" version = "1.0.43" @@ -348,18 +341,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", "rand_core 0.6.3", ] diff --git a/Cargo.toml b/Cargo.toml index 0ad9984..6ed859f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,7 @@ getrandom = { version = "0.2", features = ["js"] } hex = "0.4" hkdf = "0.12" num-bigint = { version = "0.4", features = ["rand", "serde"] } -rand = "0.8" -rand_core = { version = "0.6", features = ["getrandom"] } +rand_core = { version = "0.6", features = ["std", "getrandom"] } rand_hc = "0.3" serde = { version = "1.0", features = ["derive"] } sha2 = "0.10" diff --git a/src/symmetric_crypto/block.rs b/src/symmetric_crypto/block.rs index 907a6bb..d05d924 100644 --- a/src/symmetric_crypto/block.rs +++ b/src/symmetric_crypto/block.rs @@ -69,7 +69,8 @@ where // recover the block header and regenerate the IV let block_header = BlockHeader::::parse(&encrypted_bytes[0..block_header_len])?; - let mut ad = uid.to_vec(); + let mut ad = Vec::with_capacity(uid.len() + 8); + ad.extend_from_slice(uid); // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. // The `u64`-cast prevents build on those 32-bits machine or on // `wasm32-unknown-unknown` builds. From 36639259bd40c075473f2a4716298a22131bf4af Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 5 Sep 2022 12:15:55 +0200 Subject: [PATCH 05/18] Add `DhKeyPair` and its CurveX25519 implementation --- .../curve25519.rs} | 54 ++++++++++++++++++- src/asymmetric_crypto/mod.rs | 32 +++++++++++ src/entropy.rs | 1 + src/symmetric_crypto/block.rs | 14 ++--- src/symmetric_crypto/metadata.rs | 4 +- 5 files changed, 94 insertions(+), 11 deletions(-) rename src/{asymmetric_crypto.rs => asymmetric_crypto/curve25519.rs} (90%) create mode 100644 src/asymmetric_crypto/mod.rs diff --git a/src/asymmetric_crypto.rs b/src/asymmetric_crypto/curve25519.rs similarity index 90% rename from src/asymmetric_crypto.rs rename to src/asymmetric_crypto/curve25519.rs index 85fe17e..7111ba4 100644 --- a/src/asymmetric_crypto.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -5,7 +5,7 @@ //! Its security level is 128-bits. It is the fastest curve available at the //! time of this implementation. -use crate::{CryptoCoreError, KeyTrait}; +use crate::{asymmetric_crypto::DhKeyPair, CryptoCoreError, KeyTrait}; use curve25519_dalek::{ constants, ristretto::{CompressedRistretto, RistrettoPoint}, @@ -59,11 +59,13 @@ impl X25519PrivateKey { impl KeyTrait for X25519PrivateKey { /// Converts the given key into bytes. + #[inline] fn to_bytes(&self) -> [u8; Self::LENGTH] { self.0.to_bytes() } /// Converts the given bytes into key. + #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { Self::try_from(bytes) } @@ -100,6 +102,7 @@ impl TryFrom<&[u8]> for X25519PrivateKey { // Needed by serde to derive `Deserialize`. Do not use otherwise since there // is a copy anyway impl From for [u8; X25519_SK_LENGTH] { + #[inline] fn from(key: X25519PrivateKey) -> Self { key.0.to_bytes() } @@ -243,6 +246,7 @@ impl KeyTrait for X25519PublicKey { self.0.compress().to_bytes() } + #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { Self::try_from(bytes) } @@ -286,12 +290,14 @@ impl TryFrom<&[u8]> for X25519PublicKey { // Needed by serde to derive `Deserialize`. Do not use otherwise since there // is a copy anyway. impl From for [u8; X25519_PK_LENGTH] { + #[inline] fn from(key: X25519PublicKey) -> Self { key.0.compress().to_bytes() } } impl From<&X25519PublicKey> for [u8; X25519_PK_LENGTH] { + #[inline] fn from(key: &X25519PublicKey) -> Self { key.0.compress().to_bytes() } @@ -369,10 +375,54 @@ impl Drop for X25519PublicKey { impl ZeroizeOnDrop for X25519PublicKey {} +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct X25519KeyPair { + pk: X25519PublicKey, + sk: X25519PrivateKey, +} + +impl<'a> DhKeyPair<'a, X25519_PK_LENGTH, X25519_SK_LENGTH> for X25519KeyPair { + type PublicKey = X25519PublicKey; + + type PrivateKey = X25519PrivateKey; + + #[inline] + fn new(rng: &mut R) -> Self { + let sk = X25519PrivateKey::new(rng); + let pk = X25519PublicKey::from(&sk); + Self { sk, pk } + } + + #[inline] + fn public_key(&self) -> &Self::PublicKey { + &self.pk + } + + #[inline] + fn private_key(&self) -> &Self::PrivateKey { + &self.sk + } +} + +impl Zeroize for X25519KeyPair { + fn zeroize(&mut self) { + self.pk.zeroize(); + self.sk.zeroize(); + } +} + +impl Drop for X25519KeyPair { + fn drop(&mut self) { + self.zeroize(); + } +} + +impl ZeroizeOnDrop for X25519KeyPair {} + #[cfg(test)] mod test { use crate::{ - asymmetric_crypto::{ + asymmetric_crypto::curve25519::{ X25519PrivateKey, X25519PublicKey, X25519_PK_LENGTH, X25519_SK_LENGTH, }, entropy::CsRng, diff --git a/src/asymmetric_crypto/mod.rs b/src/asymmetric_crypto/mod.rs new file mode 100644 index 0000000..9d4ba19 --- /dev/null +++ b/src/asymmetric_crypto/mod.rs @@ -0,0 +1,32 @@ +use crate::KeyTrait; +use rand_core::{CryptoRng, RngCore}; +use core::{ + fmt::Debug, + ops::{Add, Mul}, +}; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +pub mod curve25519; + +pub trait DhKeyPair<'a, const PK_LENGTH: usize, const SK_LENGTH: usize>: + Debug + PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop +where + Self::PublicKey: Add + Mul<&'a Self::PrivateKey, Output = Self::PublicKey>, + Self::PrivateKey: 'a + Add, +{ + /// Public key + type PublicKey: KeyTrait; + + /// Secret key + type PrivateKey: KeyTrait; + + /// Create a new key pair + #[must_use] + fn new(rng: &mut R) -> Self; + + /// Return a reference to the public key. + fn public_key(&self) -> &Self::PublicKey; + + /// Return a reference to the secret key. + fn private_key(&self) -> &Self::PrivateKey; +} diff --git a/src/entropy.rs b/src/entropy.rs index 88fc050..8abee19 100644 --- a/src/entropy.rs +++ b/src/entropy.rs @@ -20,6 +20,7 @@ impl CsRng { /// Generate a vector of random bytes with the given length. /// /// - `len` : number of random bytes to generate + #[must_use] pub fn generate_random_bytes(&mut self) -> [u8; LENGTH] { let mut bytes = [0; LENGTH]; self.rng.fill_bytes(&mut bytes); diff --git a/src/symmetric_crypto/block.rs b/src/symmetric_crypto/block.rs index d05d924..780b0e8 100644 --- a/src/symmetric_crypto/block.rs +++ b/src/symmetric_crypto/block.rs @@ -74,7 +74,7 @@ where // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. // The `u64`-cast prevents build on those 32-bits machine or on // `wasm32-unknown-unknown` builds. - ad.extend(&(block_number as u64).to_le_bytes()); + ad.extend_from_slice(&(block_number as u64).to_le_bytes()); // decrypt let clear_text = S::decrypt( symmetric_key, @@ -104,11 +104,11 @@ where // get the associated data ready let mut ad = Vec::with_capacity(uid.len() + 8); - ad.extend(uid); + ad.extend_from_slice(uid); // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. // The `u64`-cast prevents build on those 32-bits machine or on // `wasm32-unknown-unknown` builds. - ad.extend(&(block_number as u64).to_le_bytes()); + ad.extend_from_slice(&(block_number as u64).to_le_bytes()); // allocate correct number of bytes let mut bytes = Vec::with_capacity( @@ -122,7 +122,7 @@ where .to_bytes(), ); // write encrypted data - bytes.extend(S::encrypt( + bytes.append(&mut S::encrypt( symmetric_key, &self.clear_text, &nonce, @@ -297,9 +297,9 @@ mod tests { let c = Bl::from_encrypted_bytes(&encrypted_bytes, &symmetric_key, &uid, 1) .expect("failed from encrypted bytes"); let mut data: Vec = vec![]; - data.extend(&data1); - data.extend(&[0_u8; 100]); - data.extend(&data2); + data.extend_from_slice(&data1); + data.extend_from_slice(&[0_u8; 100]); + data.extend_from_slice(&data2); assert_eq!(&data, c.clear_text()); } diff --git a/src/symmetric_crypto/metadata.rs b/src/symmetric_crypto/metadata.rs index 81e7082..44117c1 100644 --- a/src/symmetric_crypto/metadata.rs +++ b/src/symmetric_crypto/metadata.rs @@ -104,9 +104,9 @@ impl Metadata { } let mut bytes = Vec::with_capacity(4 + self.len()); bytes.append(&mut get_u32_len(&self.uid)?.to_vec()); - bytes.extend(&self.uid); + bytes.extend_from_slice(&self.uid); if let Some(ad) = &self.additional_data { - bytes.extend(ad); + bytes.extend_from_slice(ad); } Ok(bytes) } From bd462e9f095b0ebce6ca1bf0ab96627fdb4af8c3 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 5 Sep 2022 16:26:50 +0200 Subject: [PATCH 06/18] Remove `SymmetricCrypto` --- CHANGELOG.md | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- src/asymmetric_crypto/curve25519.rs | 11 +- src/asymmetric_crypto/mod.rs | 2 +- src/kdf.rs | 17 +- src/symmetric_crypto/aes_256_gcm_pure/dem.rs | 89 ------ src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 182 +++++++---- src/symmetric_crypto/block.rs | 306 ------------------- src/symmetric_crypto/mod.rs | 95 ++---- src/symmetric_crypto/nonce.rs | 41 +-- 11 files changed, 170 insertions(+), 579 deletions(-) delete mode 100644 src/symmetric_crypto/aes_256_gcm_pure/dem.rs delete mode 100644 src/symmetric_crypto/block.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c0e3709..9310fb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. --- -## [3.0.0] - 2022-09-02 +## [2.0.1] - 2022-09-06 ### Added ### Changed - use constant generics diff --git a/Cargo.lock b/Cargo.lock index e5c68af..890f59f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,7 +82,7 @@ dependencies = [ [[package]] name = "cosmian_crypto_core" -version = "3.0.0" +version = "2.0.1" dependencies = [ "aes-gcm", "curve25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 6ed859f..8aa6972 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Crypto lib for pure crypto primitives" edition = "2021" license = "MIT/Apache-2.0" name = "cosmian_crypto_core" -version = "3.0.0" +version = "2.0.1" [lib] crate-type = ["cdylib", "rlib"] diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index 7111ba4..0e03332 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -104,7 +104,7 @@ impl TryFrom<&[u8]> for X25519PrivateKey { impl From for [u8; X25519_SK_LENGTH] { #[inline] fn from(key: X25519PrivateKey) -> Self { - key.0.to_bytes() + key.to_bytes() } } @@ -292,14 +292,7 @@ impl TryFrom<&[u8]> for X25519PublicKey { impl From for [u8; X25519_PK_LENGTH] { #[inline] fn from(key: X25519PublicKey) -> Self { - key.0.compress().to_bytes() - } -} - -impl From<&X25519PublicKey> for [u8; X25519_PK_LENGTH] { - #[inline] - fn from(key: &X25519PublicKey) -> Self { - key.0.compress().to_bytes() + key.to_bytes() } } diff --git a/src/asymmetric_crypto/mod.rs b/src/asymmetric_crypto/mod.rs index 9d4ba19..b6195f5 100644 --- a/src/asymmetric_crypto/mod.rs +++ b/src/asymmetric_crypto/mod.rs @@ -1,9 +1,9 @@ use crate::KeyTrait; -use rand_core::{CryptoRng, RngCore}; use core::{ fmt::Debug, ops::{Add, Mul}, }; +use rand_core::{CryptoRng, RngCore}; use zeroize::{Zeroize, ZeroizeOnDrop}; pub mod curve25519; diff --git a/src/kdf.rs b/src/kdf.rs index a9b02b1..f596ec4 100644 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -1,23 +1,24 @@ use crate::CryptoCoreError; use hkdf::Hkdf; -use sha2::Sha256; +use sha2::{digest::OutputSizeUser, Sha256}; /// Derive a key of `KEY_LENGTH` bytes using a HMAC-based Extract-and-Expand /// Key Derivation Function (HKDF) supplying a `bytes` and some `info` context /// `String`. The hash function used is Sha256. /// -/// - `bytes` : input bytes to hash, should be at least 32-bytes long +/// - `ikm` : input key material, should be at least 32-bytes long /// - `info` : some optional additional information to use in the hash pub fn hkdf_256( - bytes: &[u8], + ikm: &[u8], info: &[u8], ) -> Result<[u8; LENGTH], CryptoCoreError> { - if bytes.len() < 32 { - return Err(CryptoCoreError::InvalidSize( - "Input `bytes` size should be at least 32 bytes".to_string(), - )); + if ikm.len() < ::output_size() { + return Err(CryptoCoreError::InvalidSize(format!( + "Input `bytes` size should be at least {} bytes", + ::output_size() + ))); } - let h = Hkdf::::new(None, bytes); + let h = Hkdf::::new(None, ikm); let mut out = [0; LENGTH]; h.expand(info, &mut out) .map_err(|_| CryptoCoreError::KdfError(LENGTH))?; diff --git a/src/symmetric_crypto/aes_256_gcm_pure/dem.rs b/src/symmetric_crypto/aes_256_gcm_pure/dem.rs deleted file mode 100644 index 647e466..0000000 --- a/src/symmetric_crypto/aes_256_gcm_pure/dem.rs +++ /dev/null @@ -1,89 +0,0 @@ -//! Implement the `DEM` trait for `Aes256GcmCrypto`. - -use crate::{ - symmetric_crypto::{ - aes_256_gcm_pure::{Aes256GcmCrypto, KEY_LENGTH}, - nonce::NonceTrait, - Dem, SymmetricCrypto, - }, - CryptoCoreError, -}; -use rand_core::{CryptoRng, RngCore}; -use std::convert::TryFrom; - -impl Dem for Aes256GcmCrypto { - fn encaps( - rng: &mut R, - secret_key: &[u8], - additional_data: Option<&[u8]>, - message: &[u8], - ) -> Result, CryptoCoreError> { - if secret_key.len() < KEY_LENGTH { - return Err(CryptoCoreError::SizeError { - given: secret_key.len(), - expected: KEY_LENGTH, - }); - } - // AES GCM includes an authentication method - // there is no need for parsing a MAC key - let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?; - let nonce = Self::Nonce::new(rng); - let mut c = Self::encrypt(&key, message, &nonce, additional_data) - .map_err(|err| CryptoCoreError::EncryptionError(err.to_string()))?; - // allocate correct byte number - let mut res: Vec = Vec::with_capacity(message.len() + Self::ENCAPSULATION_OVERHEAD); - res.append(&mut nonce.into()); - res.append(&mut c); - Ok(res) - } - - fn decaps( - secret_key: &[u8], - additional_data: Option<&[u8]>, - encapsulation: &[u8], - ) -> Result, CryptoCoreError> { - if secret_key.len() < KEY_LENGTH { - return Err(CryptoCoreError::SizeError { - given: secret_key.len(), - expected: KEY_LENGTH, - }); - } - // AES GCM includes an authentication method - // there is no need for parsing a MAC key - let key = Self::Key::try_from(&secret_key[..KEY_LENGTH])?; - let nonce = Self::Nonce::try_from(&encapsulation[..Self::Nonce::LENGTH])?; - Self::decrypt( - &key, - &encapsulation[Self::Nonce::LENGTH..], - &nonce, - additional_data, - ) - .map_err(|err| CryptoCoreError::EncryptionError(err.to_string())) - } -} - -#[cfg(test)] -mod tests { - - use crate::{ - entropy::CsRng, - symmetric_crypto::{aes_256_gcm_pure::Aes256GcmCrypto, Dem}, - CryptoCoreError, - }; - - #[test] - fn test_dem() -> Result<(), CryptoCoreError> { - let m = b"my secret message"; - let additional_data = Some(b"public tag".as_slice()); - let mut rng = CsRng::new(); - let secret_key = rng.generate_random_bytes::<256>(); - let c = Aes256GcmCrypto::encaps(&mut rng, &secret_key, additional_data, m)?; - let res = Aes256GcmCrypto::decaps(&secret_key, additional_data, &c)?; - if res != m { - return Err(CryptoCoreError::DecryptionError( - "Decaps failed".to_string(), - )); - } - Ok(()) - } -} diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index ed96b6b..ca63938 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -3,7 +3,7 @@ //! //! It will use the AES native interface on the CPU if available. use crate::{ - symmetric_crypto::{nonce::NonceTrait, SymKey, SymmetricCrypto}, + symmetric_crypto::{nonce::NonceTrait, Dem, SymKey}, CryptoCoreError, }; use aes_gcm::{ @@ -11,64 +11,93 @@ use aes_gcm::{ aes::cipher::generic_array::GenericArray, AeadInPlace, Aes256Gcm, KeyInit, }; -use std::fmt::Display; +use rand_core::{CryptoRng, RngCore}; -pub mod dem; +use super::{key::Key, nonce::Nonce}; /// Use a 256-bit AES key -pub const KEY_LENGTH: usize = 32; +const KEY_LENGTH: usize = 32; /// Use a 96-bit nonce -pub const NONCE_LENGTH: usize = 12; +const NONCE_LENGTH: usize = 12; /// Use a 128-bit MAC tag -pub const MAC_LENGTH: usize = 16; +const MAC_LENGTH: usize = 16; -pub type Key = crate::symmetric_crypto::key::Key; - -pub type Nonce = crate::symmetric_crypto::nonce::Nonce; +/// A 96-bit nonce restricts the plaintext size to 4096-bytes +const MAX_PLAINTEXT_LENGTH: usize = 4096; /// Structure implementing `SymmetricCrypto` and the `DEM` interfaces based on /// AES 256 GCM. pub struct Aes256GcmCrypto; -impl Display for Aes256GcmCrypto { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", Self::description()) - } -} - -impl SymmetricCrypto for Aes256GcmCrypto { - type Key = Key; - type Nonce = Nonce; +impl Dem for Aes256GcmCrypto { + const ENCRYPTION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; const MAC_LENGTH: usize = MAC_LENGTH; - fn description() -> String { - format!( - "AES 256 GCM pure Rust (key bits: {}, nonce bits: {}, tag bits: {})", - KEY_LENGTH * 8, - NONCE_LENGTH * 8, - MAC_LENGTH * 8 - ) - } + type Key = Key; - fn encrypt( - key: &Self::Key, - bytes: &[u8], - nonce: &Self::Nonce, + type Nonce = Nonce; + + fn encrypt( + rng: &mut R, + secret_key: &Self::Key, + plaintext: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { - encrypt_combined(key, bytes, nonce, additional_data) + if plaintext.len() > MAX_PLAINTEXT_LENGTH { + return Err(CryptoCoreError::InvalidSize(format!( + "Plaintext is too large ({} bytes), max size: {} ", + plaintext.len(), + MAX_PLAINTEXT_LENGTH + ))); + } + let nonce = Self::Nonce::new(rng); + // allocate correct byte number + let mut res: Vec = Vec::with_capacity(plaintext.len() + Self::ENCRYPTION_OVERHEAD); + res.extend_from_slice(nonce.as_bytes()); + res.append( + &mut encrypt_combined( + secret_key.as_bytes(), + plaintext, + nonce.as_bytes(), + additional_data, + ) + .map_err(|err| CryptoCoreError::EncryptionError(err.to_string()))?, + ); + Ok(res) } fn decrypt( - key: &Self::Key, - bytes: &[u8], - nonce: &Self::Nonce, + secret_key: &Self::Key, + ciphertext: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { - decrypt_combined(key, bytes, nonce, additional_data) + if ciphertext.len() < Self::ENCRYPTION_OVERHEAD { + return Err(CryptoCoreError::InvalidSize(format!( + "Ciphertext is too small ({} bytes), min size: {}", + ciphertext.len(), + Self::ENCRYPTION_OVERHEAD + ))); + } + if ciphertext.len() > MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD { + return Err(CryptoCoreError::InvalidSize(format!( + "Ciphertext is too large ({} bytes), max size: {} ", + ciphertext.len(), + MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD + ))); + } + // Read the nonce used for encryption. We know this will not fail since + // Self::Nonce::LENGTH < Self::ENCRYPTOION_OVERHEAD + let nonce = Self::Nonce::try_from(&ciphertext[..Self::Nonce::LENGTH])?; + decrypt_combined( + secret_key.as_bytes(), + &ciphertext[Self::Nonce::LENGTH..], + nonce.as_bytes(), + additional_data, + ) + .map_err(|err| CryptoCoreError::EncryptionError(err.to_string())) } } @@ -78,15 +107,15 @@ impl SymmetricCrypto for Aes256GcmCrypto { /// /// The total length of the encrypted data is the message length + `MAC_LENGTH` pub fn encrypt_combined( - key: &Key, + key: &[u8], bytes: &[u8], - nonce: &Nonce, + nonce: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { let payload = additional_data.map_or_else(|| Payload::from(bytes), |aad| Payload { msg: bytes, aad }); - Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) - .encrypt(GenericArray::from_slice(nonce.as_slice()), payload) + Aes256Gcm::new(GenericArray::from_slice(key)) + .encrypt(GenericArray::from_slice(nonce), payload) .map_err(|e| CryptoCoreError::EncryptionError(e.to_string())) } @@ -96,14 +125,14 @@ pub fn encrypt_combined( /// /// The tag length is `MAC_LENGTH` pub fn encrypt_in_place_detached( - key: &Key, + key: &[u8], bytes: &mut [u8], - nonce: &Nonce, + nonce: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { - Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) + Aes256Gcm::new(GenericArray::from_slice(key)) .encrypt_in_place_detached( - GenericArray::from_slice(nonce.as_slice()), + GenericArray::from_slice(nonce), additional_data.unwrap_or_default(), bytes, ) @@ -118,14 +147,14 @@ pub fn encrypt_in_place_detached( /// /// Decryption will never be performed, even partially, before verification. pub fn decrypt_combined( - key: &Key, + key: &[u8], msg: &[u8], - nonce: &Nonce, + nonce: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { let payload = additional_data.map_or_else(|| Payload::from(msg), |aad| Payload { msg, aad }); - Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) - .decrypt(GenericArray::from_slice(nonce.as_slice()), payload) + Aes256Gcm::new(GenericArray::from_slice(key)) + .decrypt(GenericArray::from_slice(nonce), payload) .map_err(|e| CryptoCoreError::DecryptionError(e.to_string())) } @@ -137,15 +166,15 @@ pub fn decrypt_combined( /// /// Decryption will never be performed, even partially, before verification. pub fn decrypt_in_place_detached( - key: &Key, + key: &[u8], bytes: &mut [u8], tag: &[u8], - nonce: &Nonce, + nonce: &[u8], additional_data: Option<&[u8]>, ) -> Result<(), CryptoCoreError> { - Aes256Gcm::new(GenericArray::from_slice(key.as_bytes())) + Aes256Gcm::new(GenericArray::from_slice(key)) .decrypt_in_place_detached( - GenericArray::from_slice(nonce.as_slice()), + GenericArray::from_slice(nonce), additional_data.unwrap_or_default(), bytes, GenericArray::from_slice(tag), @@ -161,9 +190,12 @@ mod tests { symmetric_crypto::{ aes_256_gcm_pure::{ decrypt_combined, decrypt_in_place_detached, encrypt_combined, - encrypt_in_place_detached, Key, Nonce, MAC_LENGTH, + encrypt_in_place_detached, Aes256GcmCrypto, Nonce, KEY_LENGTH, MAC_LENGTH, + NONCE_LENGTH, }, + key::Key, nonce::NonceTrait, + Dem, SymKey, }, CryptoCoreError, }; @@ -171,29 +203,29 @@ mod tests { #[test] fn test_encryption_decryption_combined() -> Result<(), CryptoCoreError> { let mut cs_rng = CsRng::new(); - let key = Key::new(&mut cs_rng); + let key = Key::::new(&mut cs_rng); let bytes = cs_rng.generate_random_bytes::<8192>(); - let iv = Nonce::new(&mut cs_rng); + let iv = Nonce::::new(&mut cs_rng); // no additional data - let encrypted_result = encrypt_combined(&key, &bytes, &iv, None)?; + let encrypted_result = encrypt_combined(&key, &bytes, iv.as_bytes(), None)?; assert_ne!(encrypted_result, bytes.to_vec()); assert_eq!(bytes.len() + MAC_LENGTH, encrypted_result.len()); - let recovered = decrypt_combined(&key, &encrypted_result, &iv, None)?; + let recovered = decrypt_combined(&key, &encrypted_result, iv.as_bytes(), None)?; assert_eq!(bytes.to_vec(), recovered); // additional data let aad = cs_rng.generate_random_bytes::<42>(); - let encrypted_result = encrypt_combined(&key, &bytes, &iv, Some(&aad))?; + let encrypted_result = encrypt_combined(&key, &bytes, iv.as_bytes(), Some(&aad))?; assert_ne!(encrypted_result, bytes.to_vec()); assert_eq!(bytes.len() + MAC_LENGTH, encrypted_result.len()); - let recovered = decrypt_combined(&key, &encrypted_result, &iv, Some(&aad))?; + let recovered = decrypt_combined(&key, &encrypted_result, iv.as_bytes(), Some(&aad))?; assert_eq!(bytes.to_vec(), recovered); // data should not be recovered if the AAD is modified let aad = cs_rng.generate_random_bytes::<42>(); - let recovered = decrypt_combined(&key, &encrypted_result, &iv, Some(&aad)); + let recovered = decrypt_combined(&key, &encrypted_result, iv.as_bytes(), Some(&aad)); assert_ne!(Ok(bytes.to_vec()), recovered); // data should not be recovered if the key is modified - let new_key = Key::new(&mut cs_rng); - let recovered = decrypt_combined(&new_key, &encrypted_result, &iv, Some(&aad)); + let new_key = Key::::new(&mut cs_rng); + let recovered = decrypt_combined(&new_key, &encrypted_result, iv.as_bytes(), Some(&aad)); assert_ne!(Ok(bytes.to_vec()), recovered); Ok(()) } @@ -201,26 +233,42 @@ mod tests { #[test] fn test_encryption_decryption_detached() -> Result<(), CryptoCoreError> { let mut cs_rng = CsRng::new(); - let key = Key::new(&mut cs_rng); + let key = Key::::new(&mut cs_rng); let bytes = cs_rng.generate_random_bytes::<8192>(); - let iv = Nonce::new(&mut cs_rng); + let iv = Nonce::::new(&mut cs_rng); // no additional data let mut data = bytes; - let tag = encrypt_in_place_detached(&key, &mut data, &iv, None)?; + let tag = encrypt_in_place_detached(&key, &mut data, iv.as_bytes(), None)?; assert_ne!(bytes, data); assert_eq!(bytes.len(), data.len()); assert_eq!(MAC_LENGTH, tag.len()); - decrypt_in_place_detached(&key, &mut data, &tag, &iv, None)?; + decrypt_in_place_detached(&key, &mut data, &tag, iv.as_bytes(), None)?; assert_eq!(bytes, data); // // additional data let ad = cs_rng.generate_random_bytes::<42>(); let mut data = bytes; - let tag = encrypt_in_place_detached(&key, &mut data, &iv, Some(&ad))?; + let tag = encrypt_in_place_detached(&key, &mut data, iv.as_bytes(), Some(&ad))?; assert_ne!(bytes, data); assert_eq!(bytes.len(), data.len()); assert_eq!(MAC_LENGTH, tag.len()); - decrypt_in_place_detached(&key, &mut data, &tag, &iv, Some(&ad))?; + decrypt_in_place_detached(key.as_bytes(), &mut data, &tag, iv.as_bytes(), Some(&ad))?; assert_eq!(bytes, data); Ok(()) } + + #[test] + fn test_dem() -> Result<(), CryptoCoreError> { + let m = b"my secret message"; + let additional_data = Some(b"public tag".as_slice()); + let mut rng = CsRng::new(); + let secret_key = Key::new(&mut rng); + let c = Aes256GcmCrypto::encrypt(&mut rng, &secret_key, m, additional_data)?; + let res = Aes256GcmCrypto::decrypt(&secret_key, &c, additional_data)?; + if res != m { + return Err(CryptoCoreError::DecryptionError( + "Decaps failed".to_string(), + )); + } + Ok(()) + } } diff --git a/src/symmetric_crypto/block.rs b/src/symmetric_crypto/block.rs deleted file mode 100644 index 780b0e8..0000000 --- a/src/symmetric_crypto/block.rs +++ /dev/null @@ -1,306 +0,0 @@ -use crate::{ - symmetric_crypto::{nonce::NonceTrait, SymmetricCrypto}, - CryptoCoreError, -}; -use rand_core::{CryptoRng, RngCore}; - -/// Block holding clear text data that needs to be encrypted. -/// -/// The max fixed length of clear text is `MAX_CLEAR_TEXT_LENGTH`. -/// The max block encrypted length is `Block::MAX_ENCRYPTED_LENGTH`. -/// -/// When calling `to_encrypted_bytes(...)` an array of bytes is generated that -/// is made of a `BlockHeader` containing the nonce, the cipher text and - -/// depending on the symmetric scheme - an authentication MAC. The nonce is -/// refreshed on each call to `to_encrypted_bytes(...)` -pub struct Block -where - S: SymmetricCrypto, -{ - clear_text: Vec, //padded with zeroes if need be - phantom_data: std::marker::PhantomData, -} - -impl - Block -where - S: SymmetricCrypto, -{ - /// Number of bytes added to the size of the input data in the output ciphertext. - pub const ENCRYPTION_OVERHEAD: usize = - BlockHeader::::LENGTH + >::MAC_LENGTH; - - /// Maximum number of bytes for an output ciphertext. - pub const MAX_ENCRYPTED_LENGTH: usize = MAX_CLEAR_TEXT_LENGTH + Self::ENCRYPTION_OVERHEAD; - - /// Creates a new empty block - #[must_use] - pub fn new() -> Self { - Self { - clear_text: vec![], - phantom_data: std::marker::PhantomData::default(), - } - } - - /// Parses a block of encrypted data to a `Block`. - /// The resource `uid` and `block_number` are part of the - /// authentication scheme amd must be re-supplied with the - /// same values used to encrypt the block - pub fn from_encrypted_bytes( - encrypted_bytes: &[u8], - symmetric_key: &>::Key, - uid: &[u8], - block_number: usize, - ) -> Result { - // The block header is always present - if encrypted_bytes.len() < Self::ENCRYPTION_OVERHEAD { - return Err(CryptoCoreError::InvalidSize(format!( - "array of encrypted data bytes of length {} is too small", - encrypted_bytes.len(), - ))); - } - if encrypted_bytes.len() > Self::MAX_ENCRYPTED_LENGTH { - return Err(CryptoCoreError::InvalidSize(format!( - "array of encrypted data bytes of length {} is too large", - encrypted_bytes.len(), - ))); - } - let block_header_len = BlockHeader::::LENGTH; - // recover the block header and regenerate the IV - let block_header = - BlockHeader::::parse(&encrypted_bytes[0..block_header_len])?; - let mut ad = Vec::with_capacity(uid.len() + 8); - ad.extend_from_slice(uid); - // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. - // The `u64`-cast prevents build on those 32-bits machine or on - // `wasm32-unknown-unknown` builds. - ad.extend_from_slice(&(block_number as u64).to_le_bytes()); - // decrypt - let clear_text = S::decrypt( - symmetric_key, - &encrypted_bytes[block_header_len..], - &block_header.nonce, - Some(&ad), - )?; - Ok(Self { - clear_text, - phantom_data: std::marker::PhantomData::default(), - }) - } - - /// Generates the encrypted data block. The nonce is refreshed on each - /// call. The resource `uid` and `block_number` are part of the AEAD and - /// must be re-supplied to decrypt the bytes. They are used to guarantee - /// that a block cannot be moved within and between resources - pub fn to_encrypted_bytes( - &self, - rng: &mut R, - symmetric_key: &>::Key, - uid: &[u8], - block_number: usize, - ) -> Result, CryptoCoreError> { - // refresh the nonce - let nonce = S::Nonce::new(rng); - - // get the associated data ready - let mut ad = Vec::with_capacity(uid.len() + 8); - ad.extend_from_slice(uid); - // Warning: `usize` can be interpreted as `u32` on 32-bits CPU-architecture. - // The `u64`-cast prevents build on those 32-bits machine or on - // `wasm32-unknown-unknown` builds. - ad.extend_from_slice(&(block_number as u64).to_le_bytes()); - - // allocate correct number of bytes - let mut bytes = Vec::with_capacity( - S::Nonce::LENGTH + S::MAC_LENGTH + self.clear_text().len() + ad.len(), - ); - // write the header - bytes.append( - &mut BlockHeader:: { - nonce: nonce.clone(), - } - .to_bytes(), - ); - // write encrypted data - bytes.append(&mut S::encrypt( - symmetric_key, - &self.clear_text, - &nonce, - Some(&ad), - )?); - Ok(bytes) - } - - /// Returns a reference to the clear text - #[must_use] - pub fn clear_text(&self) -> &[u8] { - &self.clear_text - } - - /// Moves clear text data out of the block - #[must_use] - pub fn clear_text_owned(self) -> Vec { - self.clear_text - } - - /// Writes the given clear text data in the block. Pad the block with - /// zeroes if the offset is beyond the current end of the block. - /// - /// Return the length of the data written - pub fn write(&mut self, start_offset: usize, data: &[u8]) -> Result { - if start_offset >= MAX_CLEAR_TEXT_LENGTH { - return Err(CryptoCoreError::InvalidSize(format!( - "write in block: start offset: {} is greater than max block clear text len {}", - start_offset, MAX_CLEAR_TEXT_LENGTH - ))); - } - // pad if need be - let num_to_pad = start_offset - self.clear_text.len(); - if num_to_pad > 0 { - self.clear_text.append(&mut vec![0; num_to_pad]); - } - // see what space is available - let space_left = MAX_CLEAR_TEXT_LENGTH - start_offset; - if space_left == 0 { - return Ok(0); - } - if data.len() <= space_left { - self.clear_text.extend_from_slice(data); - return Ok(data.len()); - } - self.clear_text.extend_from_slice(&data[0..space_left]); - Ok(space_left) - } -} - -impl Default for Block -where - S: SymmetricCrypto, -{ - fn default() -> Self { - Self::new() - } -} - -/// The `BlockHeader` contains the nonce/IV of an encrypted `Block` -pub struct BlockHeader -where - S: SymmetricCrypto, -{ - nonce: >::Nonce, -} - -impl BlockHeader -where - S: SymmetricCrypto, -{ - pub const LENGTH: usize = >::Nonce::LENGTH; - - pub fn parse(bytes: &[u8]) -> Result { - //TODO: use transmute to make this faster ? - Ok(Self { - nonce: <>::Nonce>::try_from_bytes(bytes)?, - }) - } - - /// Convert the block header into a slice of bytes. - pub fn as_bytes(&self) -> &[u8] { - self.nonce.as_slice() - } - - /// Convert the block header into a vector of bytes. - pub fn to_bytes(&self) -> Vec { - self.as_bytes().to_vec() - } -} - -#[cfg(test)] -mod tests { - - use super::Block; - use crate::{ - entropy::CsRng, - symmetric_crypto::aes_256_gcm_pure::{Aes256GcmCrypto, Key, KEY_LENGTH}, - }; - const MAX_CLEAR_TEXT_LENGTH: usize = 4096; - type Bl = Block; - - #[test] - fn test_empty_block() { - let b = Bl::new(); - assert!(b.clear_text().is_empty()); - - let mut cs_rng = CsRng::new(); - let symmetric_key = Key::new(&mut cs_rng); - let uid = [1_u8; 32]; - // let iv = cs_rng.generate_nonce(); - let encrypted_bytes = b - .to_encrypted_bytes(&mut cs_rng, &symmetric_key, &uid, 1) - .expect("failed to encrypted bytes"); - assert_eq!(Bl::ENCRYPTION_OVERHEAD, encrypted_bytes.len()); - let c = Bl::from_encrypted_bytes(&encrypted_bytes, &symmetric_key, &uid, 1) - .expect("failed from encrypted bytes"); - assert!(c.clear_text().is_empty()); - } - - #[test] - fn test_full_block() { - let mut cs_rng = CsRng::new(); - let symmetric_key = Key::new(&mut cs_rng); - let uid = [1_u8; 32]; - - let mut b = Bl::new(); - assert!(b.clear_text().is_empty()); - let data = cs_rng.generate_random_bytes::<16384>(); - let written = b.write(0, &data).expect("failed writing data"); - assert_eq!(MAX_CLEAR_TEXT_LENGTH, written); - - // let iv = cs_rng.generate_nonce(); - let encrypted_bytes = b - .to_encrypted_bytes(&mut cs_rng, &symmetric_key, &uid, 1) - .expect("failed to encrypted bytes"); - assert_eq!( - Bl::ENCRYPTION_OVERHEAD + MAX_CLEAR_TEXT_LENGTH, - encrypted_bytes.len() - ); - assert_eq!( - Bl::ENCRYPTION_OVERHEAD + MAX_CLEAR_TEXT_LENGTH, - Bl::MAX_ENCRYPTED_LENGTH - ); - let c = Bl::from_encrypted_bytes(&encrypted_bytes, &symmetric_key, &uid, 1) - .expect("failed from encrypted bytes"); - assert_eq!(&data[0..MAX_CLEAR_TEXT_LENGTH], c.clear_text()); - } - - #[test] - fn test_partial_block() { - let mut cs_rng = CsRng::new(); - let symmetric_key = Key::new(&mut cs_rng); - let uid = [1_u8; 32]; - - let mut b = Bl::new(); - assert!(b.clear_text().is_empty()); - - let data1 = cs_rng.generate_random_bytes::<100>(); - let written = b.write(0, &data1).expect("failed writing data"); - assert_eq!(100, written); - - let data2 = cs_rng.generate_random_bytes::<100>(); - let written = b.write(200, &data2).expect("failed writing data"); - assert_eq!(100, written); - - // let iv = cs_rng.generate_nonce(); - let encrypted_bytes = b - .to_encrypted_bytes(&mut cs_rng, &symmetric_key, &uid, 1) - .expect("failed to encrypted bytes"); - assert_eq!(300 + Bl::ENCRYPTION_OVERHEAD, encrypted_bytes.len()); - let c = Bl::from_encrypted_bytes(&encrypted_bytes, &symmetric_key, &uid, 1) - .expect("failed from encrypted bytes"); - let mut data: Vec = vec![]; - data.extend_from_slice(&data1); - data.extend_from_slice(&[0_u8; 100]); - data.extend_from_slice(&data2); - - assert_eq!(&data, c.clear_text()); - } -} diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index b874071..55ef7d4 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -6,10 +6,8 @@ pub mod aes_256_gcm_pure; pub mod key; pub mod nonce; -mod block; mod metadata; -pub use block::Block; pub use metadata::BytesScanner; pub use metadata::Metadata; @@ -30,90 +28,47 @@ pub trait SymKey: KeyTrait + Hash { fn from_bytes(bytes: [u8; LENGTH]) -> Self; } -/// Defines a symmetric encryption scheme. If this scheme is authenticated, -/// the `MAC_LENGTH` will be greater than `0`. -pub trait SymmetricCrypto: Send + Sync { - const MAC_LENGTH: usize; - type Key: SymKey; - type Nonce: NonceTrait; +/// Defines a DEM based on a symmetric scheme as defined in section 9.1 of the +/// [ISO 2004](https://www.shoup.net/iso/std6.pdf). +pub trait Dem { + /// Number of bytes added to the message length in the encapsulation. + const ENCRYPTION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; - /// A short description of the scheme - fn description() -> String; + /// MAC length + const MAC_LENGTH: usize; - /// Encrypts a message using a secret key and a public nonce in combined - /// mode. - /// - /// Append the MAC tag authenticating both the confidential and non - /// confidential data (aad) to the ciphertext. Thus, the length of the - /// encrypted data is the message length + `MAC_LENGTH`. - /// - /// It can also be used as a pur MAC by providing an empty message. - /// - /// # Parameters - /// - /// - `key` : symmetric key to use for encryption - /// - `bytes` : message bytes to encrypt - /// - `nonce` : nonce to use - /// - `aad` : additional associated data, the same data must be used - /// for decryption - fn encrypt( - key: &Self::Key, - bytes: &[u8], - nonce: &Self::Nonce, - aad: Option<&[u8]>, - ) -> Result, CryptoCoreError>; + /// Symmetric key length + const KEY_LENGTH: usize = KEY_LENGTH; - /// Decrypts a message in combined mode. - /// - /// Attempts to read a MAC appended to the ciphertext. The provided - /// additional data must match those provided during encryption for the - /// MAC to verify. Decryption will never be performed, even partially, - /// before verification. - /// - /// # Parameters - /// - /// - `key` : symmetric key to use - /// - `bytes` : encrypted bytes to decrypt (the MAC must be appended) - /// - `nonce` : nonce to use for decryption - /// - `aad` : additional associated data, the same data must be used - /// for encryption - fn decrypt( - key: &Self::Key, - bytes: &[u8], - nonce: &Self::Nonce, - aad: Option<&[u8]>, - ) -> Result, CryptoCoreError>; -} + /// Associated nonce type + type Nonce: NonceTrait; -/// Defines a DEM based on a symmetric scheme as defined in section 9.1 of the -/// [ISO 2004](https://www.shoup.net/iso/std6.pdf). -pub trait Dem: SymmetricCrypto { - /// Number of bytes added to the message length in the encapsulation. - const ENCAPSULATION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; + /// Associated key type + type Key: SymKey; - /// Encapsulate data using the given symmetric key. + /// Encrypt data using the given symmetric key. /// /// - `rng` : secure random number generator /// - `secret_key` : secret symmetric key - /// - `message` : message to encapsulate + /// - `plaintext` : plaintext message /// - `aad` : optional data to use in the authentication method, /// must use the same for decryption - fn encaps( + fn encrypt( rng: &mut R, - secret_key: &[u8], + secret_key: &Self::Key, + plaintext: &[u8], aad: Option<&[u8]>, - message: &[u8], ) -> Result, CryptoCoreError>; - /// Decapsulate data using the given symmetric key. + /// Decrypt data using the given symmetric key. /// - /// - `secret_key` : secret symmetric key - /// - `encapsulation` : message encapsulation - /// - `aad` : optional data to use in the authentication method, + /// - `secret_key` : symmetric key + /// - `ciphertext` : ciphertext message + /// - `aad` : optional data to use in the authentication method, /// must use the same for encyption - fn decaps( - secret_key: &[u8], + fn decrypt( + secret_key: &Self::Key, + ciphertext: &[u8], aad: Option<&[u8]>, - encapsulation: &[u8], ) -> Result, CryptoCoreError>; } diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index 29a9d6c..b785771 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -4,14 +4,12 @@ //! ensure a ciphertext cannot be reused, hence avoiding replay attacks. use crate::CryptoCoreError; -use num_bigint::BigUint; -use rand_core::{CryptoRng, RngCore}; -use std::{ - cmp::min, +use core::{ convert::{TryFrom, TryInto}, fmt::{Debug, Display}, - vec::Vec, }; +use num_bigint::BigUint; +use rand_core::{CryptoRng, RngCore}; /// Trait defining a nonce for use in a symmetric encryption scheme. pub trait NonceTrait: Send + Sync + Sized + Clone { @@ -35,7 +33,7 @@ pub trait NonceTrait: Send + Sync + Sized + Clone { fn xor(&self, b2: &[u8]) -> Self; /// Serialize the nonce. - fn as_slice(&self) -> &[u8]; + fn as_bytes(&self) -> &[u8]; } /// Nonce object of the given size. @@ -47,12 +45,14 @@ pub struct Nonce([u8; NONCE_LENGTH]); impl NonceTrait for Nonce { const LENGTH: usize = NONCE_LENGTH; + #[inline] fn new(rng: &mut R) -> Self { let mut bytes = [0_u8; NONCE_LENGTH]; rng.fill_bytes(&mut bytes); Self(bytes) } + #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { let b: [u8; NONCE_LENGTH] = bytes.try_into().map_err(|_| CryptoCoreError::SizeError { given: bytes.len(), @@ -61,6 +61,7 @@ impl NonceTrait for Nonce { Ok(Self(b)) } + #[inline] fn increment(&self, increment: usize) -> Self { let mut bi = BigUint::from_bytes_le(&self.0); bi += BigUint::from(increment); @@ -69,27 +70,21 @@ impl NonceTrait for Nonce { Self(bi_bytes.try_into().expect("This should never happen")) } + #[inline] fn xor(&self, b2: &[u8]) -> Self { - let mut n = self.0; - for i in 0..min(b2.len(), NONCE_LENGTH) { - n[i] ^= b2[i]; + let mut n = [0; NONCE_LENGTH]; + for (i, n_i) in n.iter_mut().enumerate() { + *n_i = self.0[i] ^ b2[i]; } Self(n) } - fn as_slice(&self) -> &[u8] { + #[inline] + fn as_bytes(&self) -> &[u8] { &self.0 } } -impl TryFrom> for Nonce { - type Error = CryptoCoreError; - - fn try_from(bytes: Vec) -> Result { - Self::try_from_bytes(&bytes) - } -} - impl<'a, const NONCE_LENGTH: usize> TryFrom<&'a [u8]> for Nonce { type Error = CryptoCoreError; @@ -104,12 +99,6 @@ impl From<[u8; NONCE_LENGTH]> for Nonce } } -impl From> for Vec { - fn from(n: Nonce) -> Self { - n.0.to_vec() - } -} - impl Display for Nonce { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex::encode(self.0)) @@ -129,9 +118,9 @@ mod tests { fn test_nonce() { let mut cs_rng = CsRng::new(); let nonce_1 = Nonce::::new(&mut cs_rng); - assert_eq!(NONCE_LENGTH, nonce_1.as_slice().len()); + assert_eq!(NONCE_LENGTH, nonce_1.as_bytes().len()); let nonce_2 = Nonce::::new(&mut cs_rng); - assert_eq!(NONCE_LENGTH, nonce_2.as_slice().len()); + assert_eq!(NONCE_LENGTH, nonce_2.as_bytes().len()); assert_ne!(nonce_1, nonce_2); } From 27694f90eed68505465c663f104e6f198fe14d4e Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 6 Sep 2022 15:33:53 +0200 Subject: [PATCH 07/18] Remove BigInt dependency --- Cargo.lock | 48 ----------------------------------- Cargo.toml | 1 - src/symmetric_crypto/nonce.rs | 42 +++++++++++++++++++++--------- 3 files changed, 30 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 890f59f..422aa3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,12 +37,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "block-buffer" version = "0.10.3" @@ -89,7 +83,6 @@ dependencies = [ "getrandom 0.2.7", "hex", "hkdf", - "num-bigint", "rand_core 0.6.3", "rand_hc", "serde", @@ -261,38 +254,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", - "rand", - "serde", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.14.0" @@ -335,15 +296,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_core 0.6.3", -] - [[package]] name = "rand_core" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 8aa6972..8f7e06f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ curve25519-dalek = "3.2" getrandom = { version = "0.2", features = ["js"] } hex = "0.4" hkdf = "0.12" -num-bigint = { version = "0.4", features = ["rand", "serde"] } rand_core = { version = "0.6", features = ["std", "getrandom"] } rand_hc = "0.3" serde = { version = "1.0", features = ["derive"] } diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index b785771..bb4138c 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -8,7 +8,6 @@ use core::{ convert::{TryFrom, TryInto}, fmt::{Debug, Display}, }; -use num_bigint::BigUint; use rand_core::{CryptoRng, RngCore}; /// Trait defining a nonce for use in a symmetric encryption scheme. @@ -26,7 +25,7 @@ pub trait NonceTrait: Send + Sync + Sized + Clone { /// Increment the nonce by the given value. #[must_use] - fn increment(&self, increment: usize) -> Self; + fn increment(&self, increment: u64) -> Self; /// Xor the nonce with the given value. #[must_use] @@ -62,12 +61,26 @@ impl NonceTrait for Nonce { } #[inline] - fn increment(&self, increment: usize) -> Self { - let mut bi = BigUint::from_bytes_le(&self.0); - bi += BigUint::from(increment); - let mut bi_bytes = bi.to_bytes_le(); - bi_bytes.resize(NONCE_LENGTH, 0); - Self(bi_bytes.try_into().expect("This should never happen")) + fn increment(&self, increment: u64) -> Self { + let increment = increment.to_le_bytes(); + assert!(NONCE_LENGTH > 8, "Consider using a longer Nonce!"); + // add the first bytes + let mut res = [0; NONCE_LENGTH]; + let mut carry = 0; + for (i, (b1, b2)) in self.0.iter().zip(increment).enumerate() { + (res[i], carry) = adc(*b1, b2, carry); + } + // take into account the potentially remaining carry + res[increment.len()] = self.0[8] + carry; + // copy the rest of the input nonce + for (res, b) in res + .iter_mut() + .rev() + .zip(self.0.iter().rev().take(NONCE_LENGTH - 7)) + { + *res = *b; + } + Self(res) } #[inline] @@ -85,6 +98,12 @@ impl NonceTrait for Nonce { } } +#[inline] +const fn adc(a: u8, b: u8, carry: u8) -> (u8, u8) { + let ret = (a as u16) + (b as u16) + (carry as u16); + (ret as u8, (ret >> 8) as u8) +} + impl<'a, const NONCE_LENGTH: usize> TryFrom<&'a [u8]> for Nonce { type Error = CryptoCoreError; @@ -100,7 +119,7 @@ impl From<[u8; NONCE_LENGTH]> for Nonce } impl Display for Nonce { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", hex::encode(self.0)) } } @@ -112,7 +131,7 @@ mod tests { symmetric_crypto::nonce::{Nonce, NonceTrait}, }; - const NONCE_LENGTH: usize = 128; + const NONCE_LENGTH: usize = 12; #[test] fn test_nonce() { @@ -126,9 +145,8 @@ mod tests { #[test] fn test_increment_nonce() { - const NONCE_LENGTH: usize = 12; let mut nonce: Nonce = Nonce::from([0_u8; NONCE_LENGTH]); - let inc = 1_usize << 10; + let inc = 1 << 10; nonce = nonce.increment(inc); println!("{}", hex::encode(nonce.0)); assert_eq!("000400000000000000000000", hex::encode(nonce.0)); From b09b3ddc3adc0c7161097cd817db469af3b014ee Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 6 Sep 2022 15:34:08 +0200 Subject: [PATCH 08/18] Remove `std` when `core` can be used --- CHANGELOG.md | 6 ++++++ src/asymmetric_crypto/curve25519.rs | 14 +++++++------- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 4 ++-- src/symmetric_crypto/key.rs | 6 +++--- src/symmetric_crypto/metadata.rs | 2 +- src/symmetric_crypto/mod.rs | 2 +- src/symmetric_crypto/nonce.rs | 2 +- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9310fb3..5b8c03c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,16 @@ All notable changes to this project will be documented in this file. --- ## [2.0.1] - 2022-09-06 ### Added +- `DhKeyPair` which represents an asymmetric key pair in a space wher the + Computational Diffie-Helman problem is intractable ### Changed - use constant generics +- `NonceTrait::increment()` does not depend on `big-int` anymore +- use `core` instead of `std` when possible ### Fixed ### Removed +- `SymmetricCrypto` trait +- `Block` --- --- diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index 0e03332..f3efb4a 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -6,6 +6,11 @@ //! time of this implementation. use crate::{asymmetric_crypto::DhKeyPair, CryptoCoreError, KeyTrait}; +use core::{ + convert::TryFrom, + fmt::Display, + ops::{Add, Mul, Sub}, +}; use curve25519_dalek::{ constants, ristretto::{CompressedRistretto, RistrettoPoint}, @@ -13,11 +18,6 @@ use curve25519_dalek::{ }; use rand_core::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; -use std::{ - convert::TryFrom, - fmt::Display, - ops::{Add, Mul, Sub}, -}; use zeroize::{Zeroize, ZeroizeOnDrop}; /// X25519 secret key length @@ -120,7 +120,7 @@ impl TryFrom<&str> for X25519PrivateKey { /// Display the hex encoded value of the key impl Display for X25519PrivateKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", hex::encode(self.0.as_bytes())) } } @@ -308,7 +308,7 @@ impl TryFrom<&str> for X25519PublicKey { /// Display the hex encoded value of the key impl Display for X25519PublicKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", hex::encode(self.0.compress().to_bytes())) } } diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index ca63938..fc7aed6 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -24,7 +24,7 @@ const NONCE_LENGTH: usize = 12; /// Use a 128-bit MAC tag const MAC_LENGTH: usize = 16; -/// A 96-bit nonce restricts the plaintext size to 4096-bytes +/// A 96-bit nonce restricts the plaintext size to 4096 bytes const MAX_PLAINTEXT_LENGTH: usize = 4096; /// Structure implementing `SymmetricCrypto` and the `DEM` interfaces based on @@ -234,7 +234,7 @@ mod tests { fn test_encryption_decryption_detached() -> Result<(), CryptoCoreError> { let mut cs_rng = CsRng::new(); let key = Key::::new(&mut cs_rng); - let bytes = cs_rng.generate_random_bytes::<8192>(); + let bytes = cs_rng.generate_random_bytes::<1024>(); let iv = Nonce::::new(&mut cs_rng); // no additional data let mut data = bytes; diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index dbd3275..0be7c83 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -1,8 +1,8 @@ //! Define a symmetric key object of variable size. use crate::{symmetric_crypto::SymKey, CryptoCoreError, KeyTrait}; +use core::{convert::TryFrom, fmt::Display, hash::Hash, ops::Deref}; use rand_core::{CryptoRng, RngCore}; -use std::{convert::TryFrom, fmt::Display, hash::Hash, ops::Deref}; use zeroize::{Zeroize, ZeroizeOnDrop}; /// Symmetric key of a given size. @@ -70,7 +70,7 @@ impl<'a, const KEY_LENGTH: usize> TryFrom<&'a [u8]> for Key { } impl Display for Key { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", hex::encode(self.as_bytes())) } } @@ -108,7 +108,7 @@ impl Deref for Key { mod tests { use crate::{entropy::CsRng, symmetric_crypto::key::Key}; - use std::ops::Deref; + use core::ops::Deref; const KEY_LENGTH: usize = 32; diff --git a/src/symmetric_crypto/metadata.rs b/src/symmetric_crypto/metadata.rs index 44117c1..9e1bf2d 100644 --- a/src/symmetric_crypto/metadata.rs +++ b/src/symmetric_crypto/metadata.rs @@ -1,6 +1,6 @@ use crate::CryptoCoreError; +use core::convert::TryInto; use serde::{Deserialize, Serialize}; -use std::convert::TryInto; /// Attempts to get the length of this slice as an `u32` in 4 endian bytes and /// returns an error if it overflows diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 55ef7d4..9fc006c 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -12,9 +12,9 @@ pub use metadata::BytesScanner; pub use metadata::Metadata; use crate::{CryptoCoreError, KeyTrait}; +use core::hash::Hash; use nonce::NonceTrait; use rand_core::{CryptoRng, RngCore}; -use std::hash::Hash; use std::vec::Vec; /// Defines a symmetric encryption key. diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index bb4138c..ff65f87 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -119,7 +119,7 @@ impl From<[u8; NONCE_LENGTH]> for Nonce } impl Display for Nonce { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", hex::encode(self.0)) } } From 62515e92b473a798104d7029dff632373c0321f0 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 6 Sep 2022 18:32:28 +0200 Subject: [PATCH 09/18] Remove `NonceTrait::increment()`. --- CHANGELOG.md | 2 +- src/symmetric_crypto/nonce.rs | 42 ----------------------------------- 2 files changed, 1 insertion(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b8c03c..bdd4fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,10 @@ All notable changes to this project will be documented in this file. Computational Diffie-Helman problem is intractable ### Changed - use constant generics -- `NonceTrait::increment()` does not depend on `big-int` anymore - use `core` instead of `std` when possible ### Fixed ### Removed +- `NonceTrait::increment()` - `SymmetricCrypto` trait - `Block` --- diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index ff65f87..bf37f04 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -23,10 +23,6 @@ pub trait NonceTrait: Send + Sync + Sized + Clone { /// `bytes` must be equal to `Self::LENGTH`. fn try_from_bytes(bytes: &[u8]) -> Result; - /// Increment the nonce by the given value. - #[must_use] - fn increment(&self, increment: u64) -> Self; - /// Xor the nonce with the given value. #[must_use] fn xor(&self, b2: &[u8]) -> Self; @@ -60,29 +56,6 @@ impl NonceTrait for Nonce { Ok(Self(b)) } - #[inline] - fn increment(&self, increment: u64) -> Self { - let increment = increment.to_le_bytes(); - assert!(NONCE_LENGTH > 8, "Consider using a longer Nonce!"); - // add the first bytes - let mut res = [0; NONCE_LENGTH]; - let mut carry = 0; - for (i, (b1, b2)) in self.0.iter().zip(increment).enumerate() { - (res[i], carry) = adc(*b1, b2, carry); - } - // take into account the potentially remaining carry - res[increment.len()] = self.0[8] + carry; - // copy the rest of the input nonce - for (res, b) in res - .iter_mut() - .rev() - .zip(self.0.iter().rev().take(NONCE_LENGTH - 7)) - { - *res = *b; - } - Self(res) - } - #[inline] fn xor(&self, b2: &[u8]) -> Self { let mut n = [0; NONCE_LENGTH]; @@ -98,12 +71,6 @@ impl NonceTrait for Nonce { } } -#[inline] -const fn adc(a: u8, b: u8, carry: u8) -> (u8, u8) { - let ret = (a as u16) + (b as u16) + (carry as u16); - (ret as u8, (ret >> 8) as u8) -} - impl<'a, const NONCE_LENGTH: usize> TryFrom<&'a [u8]> for Nonce { type Error = CryptoCoreError; @@ -142,13 +109,4 @@ mod tests { assert_eq!(NONCE_LENGTH, nonce_2.as_bytes().len()); assert_ne!(nonce_1, nonce_2); } - - #[test] - fn test_increment_nonce() { - let mut nonce: Nonce = Nonce::from([0_u8; NONCE_LENGTH]); - let inc = 1 << 10; - nonce = nonce.increment(inc); - println!("{}", hex::encode(nonce.0)); - assert_eq!("000400000000000000000000", hex::encode(nonce.0)); - } } From 6f35a5b20cc76ff48f7500f4d25bcc431042bc3b Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Wed, 7 Sep 2022 11:02:12 +0200 Subject: [PATCH 10/18] Use generic KeyPair in CoverCrypt --- src/asymmetric_crypto/curve25519.rs | 100 +++++++++++-------- src/asymmetric_crypto/mod.rs | 16 ++- src/lib.rs | 5 + src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 3 +- src/symmetric_crypto/key.rs | 58 ++++------- src/symmetric_crypto/mod.rs | 8 +- 6 files changed, 103 insertions(+), 87 deletions(-) diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index f3efb4a..68029dc 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -9,7 +9,7 @@ use crate::{asymmetric_crypto::DhKeyPair, CryptoCoreError, KeyTrait}; use core::{ convert::TryFrom, fmt::Display, - ops::{Add, Mul, Sub}, + ops::{Add, Div, Mul, Sub}, }; use curve25519_dalek::{ constants, @@ -34,30 +34,23 @@ pub const X25519_PK_LENGTH: usize = 32; pub struct X25519PrivateKey(Scalar); impl X25519PrivateKey { - /// Generate a new private key. - #[must_use] - pub fn new(rng: &mut R) -> Self { - let mut bytes = [0; 64]; - rng.fill_bytes(&mut bytes); - Self(Scalar::from_bytes_mod_order_wide(&bytes)) - } - /// Convert to bytes without copy. #[inline] #[must_use] pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() } +} - /// Invert the given key for the multiplicative law +impl KeyTrait for X25519PrivateKey { + /// Generate a new random key. #[inline] - #[must_use] - pub fn invert(&self) -> Self { - Self(self.0.invert()) + fn new(rng: &mut R) -> Self { + let mut bytes = [0; 64]; + rng.fill_bytes(&mut bytes); + Self(Scalar::from_bytes_mod_order_wide(&bytes)) } -} -impl KeyTrait for X25519PrivateKey { /// Converts the given key into bytes. #[inline] fn to_bytes(&self) -> [u8; Self::LENGTH] { @@ -181,11 +174,19 @@ impl Sub for X25519PrivateKey { } } -impl<'a> Sub<&'a Self> for X25519PrivateKey { +impl<'a> Sub<&'a X25519PrivateKey> for &X25519PrivateKey { + type Output = X25519PrivateKey; + + fn sub(self, rhs: &X25519PrivateKey) -> Self::Output { + X25519PrivateKey(self.0 - rhs.0) + } +} + +impl Mul for X25519PrivateKey { type Output = Self; - fn sub(self, rhs: &Self) -> Self::Output { - Self(self.0 - rhs.0) + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0) } } @@ -197,11 +198,21 @@ impl Sub for &X25519PrivateKey { } } -impl<'a> Sub<&'a X25519PrivateKey> for &X25519PrivateKey { +impl Div for X25519PrivateKey { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + Self(self.0 * rhs.0.invert()) + } +} + +impl<'a> Div<&'a X25519PrivateKey> for &X25519PrivateKey { type Output = X25519PrivateKey; - fn sub(self, rhs: &X25519PrivateKey) -> Self::Output { - X25519PrivateKey(self.0 - rhs.0) + fn div(self, rhs: &X25519PrivateKey) -> Self::Output { + #[allow(clippy::suspicious_arithmetic_impl)] + X25519PrivateKey(self.0 * rhs.0.invert()) } } @@ -228,18 +239,15 @@ impl ZeroizeOnDrop for X25519PrivateKey {} #[serde(try_from = "&[u8]", into = "[u8; 32]")] pub struct X25519PublicKey(RistrettoPoint); -impl X25519PublicKey { +impl KeyTrait for X25519PublicKey { /// Generate a new random public key. #[inline] - #[must_use] - pub fn new(rng: &mut R) -> Self { + fn new(rng: &mut R) -> Self { let mut uniform_bytes = [0u8; 64]; rng.fill_bytes(&mut uniform_bytes); Self(RistrettoPoint::from_uniform_bytes(&uniform_bytes)) } -} -impl KeyTrait for X25519PublicKey { /// Converts the given public key into an array of bytes. #[inline] fn to_bytes(&self) -> [u8; Self::LENGTH] { @@ -252,6 +260,12 @@ impl KeyTrait for X25519PublicKey { } } +impl From for X25519PublicKey { + fn from(private_key: X25519PrivateKey) -> Self { + Self(&private_key.0 * &constants::RISTRETTO_BASEPOINT_TABLE) + } +} + impl From<&X25519PrivateKey> for X25519PublicKey { fn from(private_key: &X25519PrivateKey) -> Self { Self(&private_key.0 * &constants::RISTRETTO_BASEPOINT_TABLE) @@ -313,18 +327,26 @@ impl Display for X25519PublicKey { } } -impl Add for X25519PublicKey { +impl Sub for X25519PublicKey { type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) } } -impl<'a> Add<&'a Self> for X25519PublicKey { +impl<'a> Sub<&'a X25519PublicKey> for &X25519PublicKey { + type Output = X25519PublicKey; + + fn sub(self, rhs: &X25519PublicKey) -> Self::Output { + X25519PublicKey(self.0 - rhs.0) + } +} + +impl Add for X25519PublicKey { type Output = Self; - fn add(self, rhs: &Self) -> Self::Output { + fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) } } @@ -337,19 +359,19 @@ impl<'a> Add<&'a X25519PublicKey> for &X25519PublicKey { } } -impl<'a> Mul<&'a X25519PrivateKey> for &X25519PublicKey { - type Output = X25519PublicKey; +impl Mul for X25519PublicKey { + type Output = Self; - fn mul(self, rhs: &X25519PrivateKey) -> Self::Output { - X25519PublicKey(self.0 * rhs.0) + fn mul(self, rhs: X25519PrivateKey) -> Self::Output { + Self(self.0 * rhs.0) } } -impl<'a> Mul<&'a X25519PrivateKey> for X25519PublicKey { - type Output = Self; +impl<'a> Mul<&'a X25519PrivateKey> for &X25519PublicKey { + type Output = X25519PublicKey; fn mul(self, rhs: &X25519PrivateKey) -> Self::Output { - Self(self.0 * rhs.0) + X25519PublicKey(self.0 * rhs.0) } } @@ -374,7 +396,7 @@ pub struct X25519KeyPair { sk: X25519PrivateKey, } -impl<'a> DhKeyPair<'a, X25519_PK_LENGTH, X25519_SK_LENGTH> for X25519KeyPair { +impl DhKeyPair for X25519KeyPair { type PublicKey = X25519PublicKey; type PrivateKey = X25519PrivateKey; diff --git a/src/asymmetric_crypto/mod.rs b/src/asymmetric_crypto/mod.rs index b6195f5..8176800 100644 --- a/src/asymmetric_crypto/mod.rs +++ b/src/asymmetric_crypto/mod.rs @@ -1,19 +1,27 @@ use crate::KeyTrait; use core::{ fmt::Debug, - ops::{Add, Mul}, + ops::{Add, Div, Mul, Sub}, }; use rand_core::{CryptoRng, RngCore}; use zeroize::{Zeroize, ZeroizeOnDrop}; pub mod curve25519; -pub trait DhKeyPair<'a, const PK_LENGTH: usize, const SK_LENGTH: usize>: +pub trait DhKeyPair: Debug + PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop where - Self::PublicKey: Add + Mul<&'a Self::PrivateKey, Output = Self::PublicKey>, - Self::PrivateKey: 'a + Add, + Self::PublicKey: From + Add + Mul, + Self::PrivateKey: Add + Sub + Mul + Div, { + /// This is needed to be able to use `{ MyKeyPair::PK_LENGTH }` + /// as associated constant + const PK_LENGTH: usize = PK_LENGTH; + + /// This is needed to be able to use `{ MyKeyPair::SK_LENGTH }` + /// as associated constant + const SK_LENGTH: usize = SK_LENGTH; + /// Public key type PublicKey: KeyTrait; diff --git a/src/lib.rs b/src/lib.rs index 8e682aa..1e0b95c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub mod entropy; pub mod kdf; pub mod symmetric_crypto; +use rand_core::{CryptoRng, RngCore}; use zeroize::{Zeroize, ZeroizeOnDrop}; pub use crate::error::CryptoCoreError; @@ -34,6 +35,10 @@ pub trait KeyTrait: /// Key length const LENGTH: usize = LENGTH; + /// Generate a new random key. + #[must_use] + fn new(rng: &mut R) -> Self; + /// Convert the given key into a vector of bytes. #[must_use] fn to_bytes(&self) -> [u8; LENGTH]; diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index fc7aed6..cea8798 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -29,6 +29,7 @@ const MAX_PLAINTEXT_LENGTH: usize = 4096; /// Structure implementing `SymmetricCrypto` and the `DEM` interfaces based on /// AES 256 GCM. +#[derive(Debug, PartialEq, Eq)] pub struct Aes256GcmCrypto; impl Dem for Aes256GcmCrypto { @@ -197,7 +198,7 @@ mod tests { nonce::NonceTrait, Dem, SymKey, }, - CryptoCoreError, + CryptoCoreError, KeyTrait, }; #[test] diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index 0be7c83..36377bc 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -11,16 +11,15 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; #[derive(Debug, Hash, Clone, PartialEq, Eq)] pub struct Key([u8; LENGTH]); -impl Key { +impl KeyTrait for Key { /// Generate a new symmetric random `Key` - pub fn new(rng: &mut R) -> Self { - let mut key = [0; KEY_LENGTH]; + #[inline] + fn new(rng: &mut R) -> Self { + let mut key = [0; LENGTH]; rng.fill_bytes(&mut key); Self(key) } -} -impl KeyTrait for Key { /// Convert the given key into bytes. #[inline] fn to_bytes(&self) -> [u8; LENGTH] { @@ -30,42 +29,29 @@ impl KeyTrait for Key { /// Try to convert the given bytes into a key. Size must be correct. #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { - Self::try_from(bytes) + let bytes = <[u8; LENGTH]>::try_from(bytes) + .map_err(|e| CryptoCoreError::ConversionError(e.to_string()))?; + Ok(Self(bytes)) } } -impl SymKey for Key { +impl SymKey for Key { /// Convert the given key into a byte slice. #[inline] fn as_bytes(&self) -> &[u8] { &self.0 } - /// Convert the given bytes with correct size into a key. - fn from_bytes(bytes: [u8; KEY_LENGTH]) -> Self { - Self(bytes) - } -} - -impl From> for [u8; KEY_LENGTH] { - fn from(k: Key) -> Self { - k.0 - } -} - -impl From<[u8; KEY_LENGTH]> for Key { - fn from(b: [u8; KEY_LENGTH]) -> Self { - Self(b) + /// Consume the key to return underlying bytes. + #[inline] + fn into_bytes(self) -> [u8; LENGTH] { + self.0 } -} -impl<'a, const KEY_LENGTH: usize> TryFrom<&'a [u8]> for Key { - type Error = CryptoCoreError; - - fn try_from(bytes: &'a [u8]) -> Result { - let bytes = <[u8; KEY_LENGTH]>::try_from(bytes) - .map_err(|e| Self::Error::ConversionError(e.to_string()))?; - Ok(Self(bytes)) + /// Convert the given bytes with correct size into a key. + #[inline] + fn from_bytes(bytes: [u8; LENGTH]) -> Self { + Self(bytes) } } @@ -107,8 +93,7 @@ impl Deref for Key { #[cfg(test)] mod tests { - use crate::{entropy::CsRng, symmetric_crypto::key::Key}; - use core::ops::Deref; + use crate::{entropy::CsRng, symmetric_crypto::key::Key, KeyTrait}; const KEY_LENGTH: usize = 32; @@ -121,13 +106,4 @@ mod tests { assert_eq!(KEY_LENGTH, key_2.len()); assert_ne!(key_1, key_2); } - - #[test] - fn test_key_serialization() { - let mut cs_rng = CsRng::new(); - let key = Key::<32>::new(&mut cs_rng); - let bytes = <[u8; 32]>::try_from(key.deref()).unwrap(); - let res = Key::try_from(bytes).unwrap(); - assert_eq!(key, res); - } } diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 9fc006c..41cf55d 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -12,7 +12,7 @@ pub use metadata::BytesScanner; pub use metadata::Metadata; use crate::{CryptoCoreError, KeyTrait}; -use core::hash::Hash; +use core::{fmt::Debug, hash::Hash}; use nonce::NonceTrait; use rand_core::{CryptoRng, RngCore}; use std::vec::Vec; @@ -23,6 +23,10 @@ pub trait SymKey: KeyTrait + Hash { #[must_use] fn as_bytes(&self) -> &[u8]; + /// Consume the key to return underlying bytes. + #[must_use] + fn into_bytes(self) -> [u8; LENGTH]; + /// Convert the given bytes into a key. #[must_use] fn from_bytes(bytes: [u8; LENGTH]) -> Self; @@ -30,7 +34,7 @@ pub trait SymKey: KeyTrait + Hash { /// Defines a DEM based on a symmetric scheme as defined in section 9.1 of the /// [ISO 2004](https://www.shoup.net/iso/std6.pdf). -pub trait Dem { +pub trait Dem: Debug + PartialEq { /// Number of bytes added to the message length in the encapsulation. const ENCRYPTION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; From 6cc99e6fe30bad2d0f9304d6d567a4274a82f09d Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 12 Sep 2022 15:49:43 +0200 Subject: [PATCH 11/18] Corrections --- Cargo.lock | 24 ++++++++++---------- src/asymmetric_crypto/curve25519.rs | 8 ------- src/lib.rs | 2 +- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 22 +++++++----------- src/symmetric_crypto/key.rs | 6 ----- src/symmetric_crypto/nonce.rs | 8 +++---- 6 files changed, 25 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 422aa3a..a885c16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,9 +232,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -433,9 +433,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -443,9 +443,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", @@ -458,9 +458,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -468,9 +468,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -481,9 +481,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "zeroize" diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index 68029dc..f7aedf2 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -190,14 +190,6 @@ impl Mul for X25519PrivateKey { } } -impl Sub for &X25519PrivateKey { - type Output = X25519PrivateKey; - - fn sub(self, rhs: X25519PrivateKey) -> Self::Output { - X25519PrivateKey(self.0 - rhs.0) - } -} - impl Div for X25519PrivateKey { type Output = Self; diff --git a/src/lib.rs b/src/lib.rs index 1e0b95c..5bbad70 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ pub mod reexport { /// Trait defining a cryptographic key. pub trait KeyTrait: - PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop + Clone + Eq + PartialEq + Send + Sized + Sync + Zeroize + ZeroizeOnDrop { /// Key length const LENGTH: usize = LENGTH; diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index cea8798..2ab222b 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -58,15 +58,12 @@ impl Dem for Aes256GcmCrypto { // allocate correct byte number let mut res: Vec = Vec::with_capacity(plaintext.len() + Self::ENCRYPTION_OVERHEAD); res.extend_from_slice(nonce.as_bytes()); - res.append( - &mut encrypt_combined( - secret_key.as_bytes(), - plaintext, - nonce.as_bytes(), - additional_data, - ) - .map_err(|err| CryptoCoreError::EncryptionError(err.to_string()))?, - ); + res.append(&mut encrypt_combined( + secret_key.as_bytes(), + plaintext, + nonce.as_bytes(), + additional_data, + )?); Ok(res) } @@ -89,16 +86,13 @@ impl Dem for Aes256GcmCrypto { MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD ))); } - // Read the nonce used for encryption. We know this will not fail since - // Self::Nonce::LENGTH < Self::ENCRYPTOION_OVERHEAD - let nonce = Self::Nonce::try_from(&ciphertext[..Self::Nonce::LENGTH])?; + // The ciphertext is of the form: nonce || AEAS ciphertext decrypt_combined( secret_key.as_bytes(), &ciphertext[Self::Nonce::LENGTH..], - nonce.as_bytes(), + &ciphertext[..Self::Nonce::LENGTH], additional_data, ) - .map_err(|err| CryptoCoreError::EncryptionError(err.to_string())) } } diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index 36377bc..1852faf 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -61,12 +61,6 @@ impl Display for Key { } } -impl Default for Key { - fn default() -> Self { - Self([0; KEY_LENGTH]) - } -} - impl Zeroize for Key { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index bf37f04..b0dc442 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -42,7 +42,7 @@ impl NonceTrait for Nonce { #[inline] fn new(rng: &mut R) -> Self { - let mut bytes = [0_u8; NONCE_LENGTH]; + let mut bytes = [0; NONCE_LENGTH]; rng.fill_bytes(&mut bytes); Self(bytes) } @@ -58,9 +58,9 @@ impl NonceTrait for Nonce { #[inline] fn xor(&self, b2: &[u8]) -> Self { - let mut n = [0; NONCE_LENGTH]; - for (i, n_i) in n.iter_mut().enumerate() { - *n_i = self.0[i] ^ b2[i]; + let mut n = self.0; + for (ni, bi) in n.iter_mut().zip(b2) { + *ni ^= bi } Self(n) } From 02ae7220e731801f38e9b50256551272636c4d40 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Mon, 19 Sep 2022 18:04:34 +0200 Subject: [PATCH 12/18] Remove arithmetic implementations without reference for curve25519 keys --- Cargo.lock | 42 +++++++------- src/asymmetric_crypto/curve25519.rs | 89 ++--------------------------- src/asymmetric_crypto/mod.rs | 9 ++- 3 files changed, 32 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a885c16..16ed0b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,7 +83,7 @@ dependencies = [ "getrandom 0.2.7", "hex", "hkdf", - "rand_core 0.6.3", + "rand_core 0.6.4", "rand_hc", "serde", "sha2", @@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.3", + "rand_core 0.6.4", "typenum", ] @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ "block-buffer", "crypto-common", @@ -218,7 +218,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.132" +version = "0.2.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" [[package]] name = "log" @@ -307,9 +307,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.7", ] @@ -320,7 +320,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -345,13 +345,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -362,9 +362,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" dependencies = [ "proc-macro2", "quote", @@ -373,18 +373,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" +checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" +checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" dependencies = [ "proc-macro2", "quote", @@ -399,9 +399,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" [[package]] name = "universal-hash" diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index f7aedf2..49d0d2c 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -118,46 +118,6 @@ impl Display for X25519PrivateKey { } } -impl<'a> Mul<&'a Self> for X25519PrivateKey { - type Output = Self; - - fn mul(self, rhs: &Self) -> Self::Output { - Self(self.0 * rhs.0) - } -} - -impl<'a> Mul<&'a X25519PrivateKey> for &X25519PrivateKey { - type Output = X25519PrivateKey; - - fn mul(self, rhs: &X25519PrivateKey) -> Self::Output { - X25519PrivateKey(self.0 * rhs.0) - } -} - -impl Add for X25519PrivateKey { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl<'a> Add<&'a Self> for X25519PrivateKey { - type Output = Self; - - fn add(self, rhs: &Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - -impl<'a> Add for &'a X25519PrivateKey { - type Output = X25519PrivateKey; - - fn add(self, rhs: X25519PrivateKey) -> Self::Output { - X25519PrivateKey(self.0 + rhs.0) - } -} - impl<'a> Add<&'a X25519PrivateKey> for &X25519PrivateKey { type Output = X25519PrivateKey; @@ -166,14 +126,6 @@ impl<'a> Add<&'a X25519PrivateKey> for &X25519PrivateKey { } } -impl Sub for X25519PrivateKey { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - impl<'a> Sub<&'a X25519PrivateKey> for &X25519PrivateKey { type Output = X25519PrivateKey; @@ -182,20 +134,11 @@ impl<'a> Sub<&'a X25519PrivateKey> for &X25519PrivateKey { } } -impl Mul for X25519PrivateKey { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self(self.0 * rhs.0) - } -} - -impl Div for X25519PrivateKey { - type Output = Self; +impl<'a> Mul<&'a X25519PrivateKey> for &X25519PrivateKey { + type Output = X25519PrivateKey; - fn div(self, rhs: Self) -> Self::Output { - #[allow(clippy::suspicious_arithmetic_impl)] - Self(self.0 * rhs.0.invert()) + fn mul(self, rhs: &X25519PrivateKey) -> Self::Output { + X25519PrivateKey(self.0 * rhs.0) } } @@ -319,14 +262,6 @@ impl Display for X25519PublicKey { } } -impl Sub for X25519PublicKey { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Self(self.0 - rhs.0) - } -} - impl<'a> Sub<&'a X25519PublicKey> for &X25519PublicKey { type Output = X25519PublicKey; @@ -335,14 +270,6 @@ impl<'a> Sub<&'a X25519PublicKey> for &X25519PublicKey { } } -impl Add for X25519PublicKey { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self(self.0 + rhs.0) - } -} - impl<'a> Add<&'a X25519PublicKey> for &X25519PublicKey { type Output = X25519PublicKey; @@ -351,14 +278,6 @@ impl<'a> Add<&'a X25519PublicKey> for &X25519PublicKey { } } -impl Mul for X25519PublicKey { - type Output = Self; - - fn mul(self, rhs: X25519PrivateKey) -> Self::Output { - Self(self.0 * rhs.0) - } -} - impl<'a> Mul<&'a X25519PrivateKey> for &X25519PublicKey { type Output = X25519PublicKey; diff --git a/src/asymmetric_crypto/mod.rs b/src/asymmetric_crypto/mod.rs index 8176800..4696213 100644 --- a/src/asymmetric_crypto/mod.rs +++ b/src/asymmetric_crypto/mod.rs @@ -11,8 +11,13 @@ pub mod curve25519; pub trait DhKeyPair: Debug + PartialEq + Eq + Send + Sync + Sized + Clone + Zeroize + ZeroizeOnDrop where - Self::PublicKey: From + Add + Mul, - Self::PrivateKey: Add + Sub + Mul + Div, + Self::PublicKey: From, + for<'a, 'b> &'a Self::PublicKey: Add<&'b Self::PublicKey, Output = Self::PublicKey> + + Mul<&'b Self::PrivateKey, Output = Self::PublicKey>, + for<'a, 'b> &'a Self::PrivateKey: Add<&'b Self::PrivateKey, Output = Self::PrivateKey> + + Sub<&'b Self::PrivateKey, Output = Self::PrivateKey> + + Mul<&'b Self::PrivateKey, Output = Self::PrivateKey> + + Div<&'b Self::PrivateKey, Output = Self::PrivateKey>, { /// This is needed to be able to use `{ MyKeyPair::PK_LENGTH }` /// as associated constant From c702042c240cc7222fc3648166bbff7b01f34a78 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 20 Sep 2022 10:40:58 +0200 Subject: [PATCH 13/18] Bump version number to v3.0.0 --- CHANGELOG.md | 2 +- Cargo.lock | 2 +- Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdd4fe4..e8344ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. --- -## [2.0.1] - 2022-09-06 +## [3.0.0] - 2022-09-20 ### Added - `DhKeyPair` which represents an asymmetric key pair in a space wher the Computational Diffie-Helman problem is intractable diff --git a/Cargo.lock b/Cargo.lock index 16ed0b6..e6bdcf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,7 +76,7 @@ dependencies = [ [[package]] name = "cosmian_crypto_core" -version = "2.0.1" +version = "3.0.0" dependencies = [ "aes-gcm", "curve25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 8f7e06f..49eb29b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Crypto lib for pure crypto primitives" edition = "2021" license = "MIT/Apache-2.0" name = "cosmian_crypto_core" -version = "2.0.1" +version = "3.0.0" [lib] crate-type = ["cdylib", "rlib"] From b82ca5cdc4b078c9acd777910a644f372a61fc3c Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 20 Sep 2022 12:40:44 +0200 Subject: [PATCH 14/18] Correct plaintext size limitation --- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 11 ++++++----- src/symmetric_crypto/mod.rs | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index 2ab222b..05568a0 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -24,8 +24,9 @@ const NONCE_LENGTH: usize = 12; /// Use a 128-bit MAC tag const MAC_LENGTH: usize = 16; -/// A 96-bit nonce restricts the plaintext size to 4096 bytes -const MAX_PLAINTEXT_LENGTH: usize = 4096; +/// Plaintext size (in bytes) restriction from the NIST +/// https://csrc.nist.gov/publications/detail/sp/800-38d/final +const MAX_PLAINTEXT_LENGTH: u64 = 68_719_476_704; // (2 ^ 39 - 256) / 8 /// Structure implementing `SymmetricCrypto` and the `DEM` interfaces based on /// AES 256 GCM. @@ -47,7 +48,7 @@ impl Dem for Aes256GcmCrypto { plaintext: &[u8], additional_data: Option<&[u8]>, ) -> Result, CryptoCoreError> { - if plaintext.len() > MAX_PLAINTEXT_LENGTH { + if plaintext.len() as u64 > MAX_PLAINTEXT_LENGTH { return Err(CryptoCoreError::InvalidSize(format!( "Plaintext is too large ({} bytes), max size: {} ", plaintext.len(), @@ -79,11 +80,11 @@ impl Dem for Aes256GcmCrypto { Self::ENCRYPTION_OVERHEAD ))); } - if ciphertext.len() > MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD { + if ciphertext.len() as u64 > MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD as u64 { return Err(CryptoCoreError::InvalidSize(format!( "Ciphertext is too large ({} bytes), max size: {} ", ciphertext.len(), - MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD + MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD as u64 ))); } // The ciphertext is of the form: nonce || AEAS ciphertext diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 41cf55d..70c5bda 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -54,7 +54,7 @@ pub trait Dem: Debug + PartialEq { /// /// - `rng` : secure random number generator /// - `secret_key` : secret symmetric key - /// - `plaintext` : plaintext message + /// - `plaintext` : plaintext message /// - `aad` : optional data to use in the authentication method, /// must use the same for decryption fn encrypt( From fe1a25e7638bbc17b0d6e3fa03e9900fc198be7b Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Wed, 21 Sep 2022 09:17:49 +0200 Subject: [PATCH 15/18] Add test on `X225519KeyPair` --- src/asymmetric_crypto/curve25519.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index 49d0d2c..a114279 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -347,13 +347,7 @@ impl ZeroizeOnDrop for X25519KeyPair {} #[cfg(test)] mod test { - use crate::{ - asymmetric_crypto::curve25519::{ - X25519PrivateKey, X25519PublicKey, X25519_PK_LENGTH, X25519_SK_LENGTH, - }, - entropy::CsRng, - KeyTrait, - }; + use crate::{asymmetric_crypto::curve25519::*, entropy::CsRng, KeyTrait}; #[test] fn test_private_key_serialization() { @@ -372,4 +366,18 @@ mod test { let recovered = super::X25519PublicKey::try_from(bytes).unwrap(); assert_eq!(pk, recovered); } + + #[test] + fn test_dh_key_pair() { + let mut rng = CsRng::new(); + let kp1 = X25519KeyPair::new(&mut rng); + let kp2 = X25519KeyPair::new(&mut rng); + // check the keys are randomly generated + assert_ne!(kp1, kp2); + // check DH Key exchange is possible + assert_eq!( + kp1.public_key() * kp2.private_key(), + kp2.public_key() * kp1.private_key() + ); + } } From 631049f5f02ab022b6894c67680c6936c7a948fa Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 4 Oct 2022 10:33:08 +0200 Subject: [PATCH 16/18] fix(security)!: remove HKDF BREAKING CHANGE: implementations should use a SHA algorithm (preferentially SHA-3 since Intel processors will include dedicated NI in the long run) if the input has enough entropy, Argon2 or a PBKDF otherwise (see ANSSI specification about this). --- Cargo.lock | 36 ++++++++++++++++++------------------ src/kdf.rs | 26 -------------------------- src/lib.rs | 1 - 3 files changed, 18 insertions(+), 45 deletions(-) delete mode 100644 src/kdf.rs diff --git a/Cargo.lock b/Cargo.lock index e6bdcf3..1b77414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "ctr" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d14f329cfbaf5d0e06b5e87fff7e265d2673c5ea7d2c27691a2c107db1442a0" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.133" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "log" @@ -256,9 +256,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" [[package]] name = "opaque-debug" @@ -280,9 +280,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" dependencies = [ "unicode-ident", ] @@ -325,18 +325,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -362,9 +362,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" dependencies = [ "proc-macro2", "quote", @@ -373,18 +373,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", diff --git a/src/kdf.rs b/src/kdf.rs deleted file mode 100644 index f596ec4..0000000 --- a/src/kdf.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::CryptoCoreError; -use hkdf::Hkdf; -use sha2::{digest::OutputSizeUser, Sha256}; - -/// Derive a key of `KEY_LENGTH` bytes using a HMAC-based Extract-and-Expand -/// Key Derivation Function (HKDF) supplying a `bytes` and some `info` context -/// `String`. The hash function used is Sha256. -/// -/// - `ikm` : input key material, should be at least 32-bytes long -/// - `info` : some optional additional information to use in the hash -pub fn hkdf_256( - ikm: &[u8], - info: &[u8], -) -> Result<[u8; LENGTH], CryptoCoreError> { - if ikm.len() < ::output_size() { - return Err(CryptoCoreError::InvalidSize(format!( - "Input `bytes` size should be at least {} bytes", - ::output_size() - ))); - } - let h = Hkdf::::new(None, ikm); - let mut out = [0; LENGTH]; - h.expand(info, &mut out) - .map_err(|_| CryptoCoreError::KdfError(LENGTH))?; - Ok(out) -} diff --git a/src/lib.rs b/src/lib.rs index 5bbad70..02e6fb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ mod error; pub mod asymmetric_crypto; pub mod entropy; -pub mod kdf; pub mod symmetric_crypto; use rand_core::{CryptoRng, RngCore}; From 6f892886cc0fcab7a8e03b9154c54542972b2634 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 4 Oct 2022 10:57:42 +0200 Subject: [PATCH 17/18] fix: review `README.md` and `CHANGELOG.md` --- CHANGELOG.md | 3 ++- README.md | 21 ++++++--------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8344ec..75d2d3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. --- -## [3.0.0] - 2022-09-20 +## [3.0.0] - 2022-10-04 ### Added - `DhKeyPair` which represents an asymmetric key pair in a space wher the Computational Diffie-Helman problem is intractable @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - `NonceTrait::increment()` - `SymmetricCrypto` trait - `Block` +- `kdf` module --- --- diff --git a/README.md b/README.md index 8ff76c3..c6fb4dc 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Cosmian cryptographic resources: - symmetric cryptography primitives can be found in the `symmetric_crypto` module; - asymmetric cryptography primitives can be found in the `asymmetric_crypto` module; -- a Key Derivation Function (KDF) can be found in the `kdf` module; - a Random Number Generator (RNG) can be found in the `entropy` module. The crate also defines `CryptoCoreError`, the error type, and a few traits. @@ -23,28 +22,20 @@ GCM algorithm, as described in the [ISO 2004](https://www.shoup.net/iso/std6.pdf This implementation is 128-bits secure. It uses the [`aes_gcm`](https://docs.rs/aes-gcm/latest/aes_gcm/index.html) -implementation of the AES GCM algorithm. This implementation make use of the -AES instruction when available, which allows a high encryption speed. +implementation of the AES GCM algorithm. This implementation makes use of the +AES instruction set when available, which allows for a high encryption speed. ## Asymmetric Crypto This crate implements a public and a private key objects based on Curve25519. -This is the fastest elliptic curve known when implementing these objects. Its -security level is also 128 bits. +This one of the fastest elliptic curves known when implementing these objects. +Its security level is also 128 bits. It uses the [Dalek](https://github.com/dalek-cryptography/curve25519-dalek) -implementation, which also offers an implementation of the Ristretto technique -to construct a prime order group on the curve. This group is used to implement +implementation, which offers an implementation of the Ristretto technique to +construct a prime order group on the curve. This group is used to implement the public key. -## Key Derivation Function (KDF) - -This crate uses the [`hkdf`](https://docs.rs/hkdf/latest/hkdf/) implementation -of the HKDF algorithm, along with the Sha256 implementation of the Rust standard -library in order to implement a KDF. - -Since Sha256 is 128-bits secure, this makes this KDF 128-bits secure too. - ## Random Number Generator (RNG) This crate uses the implementation of the HC128 algorithm from the From fd8224ad647b9af1bb2c4ccdf2549cedf71dc2a6 Mon Sep 17 00:00:00 2001 From: Theophile BREZOT Date: Tue, 4 Oct 2022 11:34:10 +0200 Subject: [PATCH 18/18] fix(documentation): review documentation + add inline directives Fix typos, increase homogeneity and add inline proc macros when possible. --- src/asymmetric_crypto/curve25519.rs | 16 +++++---- src/asymmetric_crypto/mod.rs | 6 ++-- src/entropy.rs | 14 +++++--- src/error.rs | 2 +- src/lib.rs | 12 +++---- src/symmetric_crypto/aes_256_gcm_pure/mod.rs | 8 ++--- src/symmetric_crypto/key.rs | 14 ++++---- src/symmetric_crypto/metadata.rs | 37 ++++++++++++-------- src/symmetric_crypto/mod.rs | 12 +++---- src/symmetric_crypto/nonce.rs | 12 +++---- 10 files changed, 75 insertions(+), 58 deletions(-) diff --git a/src/asymmetric_crypto/curve25519.rs b/src/asymmetric_crypto/curve25519.rs index a114279..0a88fbe 100644 --- a/src/asymmetric_crypto/curve25519.rs +++ b/src/asymmetric_crypto/curve25519.rs @@ -34,7 +34,7 @@ pub const X25519_PK_LENGTH: usize = 32; pub struct X25519PrivateKey(Scalar); impl X25519PrivateKey { - /// Convert to bytes without copy. + /// Converts to bytes without copy. #[inline] #[must_use] pub fn as_bytes(&self) -> &[u8] { @@ -43,7 +43,7 @@ impl X25519PrivateKey { } impl KeyTrait for X25519PrivateKey { - /// Generate a new random key. + /// Generates a new random key. #[inline] fn new(rng: &mut R) -> Self { let mut bytes = [0; 64]; @@ -157,7 +157,7 @@ impl Zeroize for X25519PrivateKey { } } -// Implement `Drop` trait to follow R23. +// Implements `Drop` trait to follow R23. impl Drop for X25519PrivateKey { fn drop(&mut self) { self.zeroize(); @@ -175,7 +175,7 @@ impl ZeroizeOnDrop for X25519PrivateKey {} pub struct X25519PublicKey(RistrettoPoint); impl KeyTrait for X25519PublicKey { - /// Generate a new random public key. + /// Generates a new random public key. #[inline] fn new(rng: &mut R) -> Self { let mut uniform_bytes = [0u8; 64]; @@ -189,6 +189,7 @@ impl KeyTrait for X25519PublicKey { self.0.compress().to_bytes() } + /// Converts the given bytes into key. #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { Self::try_from(bytes) @@ -245,7 +246,7 @@ impl From for [u8; X25519_PK_LENGTH] { } } -/// Parse from an hex encoded String +/// Parses an hex encoded String impl TryFrom<&str> for X25519PublicKey { type Error = CryptoCoreError; @@ -255,7 +256,7 @@ impl TryFrom<&str> for X25519PublicKey { } } -/// Display the hex encoded value of the key +/// Displays the hex encoded value of the key impl Display for X25519PublicKey { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", hex::encode(self.0.compress().to_bytes())) @@ -292,7 +293,7 @@ impl Zeroize for X25519PublicKey { } } -// Implement `Drop` trait to follow R23. +// Implements `Drop` trait to follow R23. impl Drop for X25519PublicKey { fn drop(&mut self) { self.zeroize(); @@ -337,6 +338,7 @@ impl Zeroize for X25519KeyPair { } } +// Implements `Drop` trait to follow R23. impl Drop for X25519KeyPair { fn drop(&mut self) { self.zeroize(); diff --git a/src/asymmetric_crypto/mod.rs b/src/asymmetric_crypto/mod.rs index 4696213..5184b23 100644 --- a/src/asymmetric_crypto/mod.rs +++ b/src/asymmetric_crypto/mod.rs @@ -33,13 +33,13 @@ where /// Secret key type PrivateKey: KeyTrait; - /// Create a new key pair + /// Creates a new key pair #[must_use] fn new(rng: &mut R) -> Self; - /// Return a reference to the public key. + /// Returns a reference to the public key. fn public_key(&self) -> &Self::PublicKey; - /// Return a reference to the secret key. + /// Returns a reference to the secret key. fn private_key(&self) -> &Self::PrivateKey; } diff --git a/src/entropy.rs b/src/entropy.rs index 8abee19..0ebf062 100644 --- a/src/entropy.rs +++ b/src/entropy.rs @@ -9,7 +9,8 @@ pub struct CsRng { } impl CsRng { - /// Generate a new random number generator. + /// Generates a new random number generator. + #[inline] #[must_use] pub fn new() -> Self { Self { @@ -17,9 +18,8 @@ impl CsRng { } } - /// Generate a vector of random bytes with the given length. - /// - /// - `len` : number of random bytes to generate + /// Generates a vector of random bytes with the given length. + #[inline] #[must_use] pub fn generate_random_bytes(&mut self) -> [u8; LENGTH] { let mut bytes = [0; LENGTH]; @@ -29,24 +29,30 @@ impl CsRng { } impl Default for CsRng { + #[must_use] + #[inline] fn default() -> Self { Self::new() } } impl RngCore for CsRng { + #[inline] fn next_u32(&mut self) -> u32 { self.rng.next_u32() } + #[inline] fn next_u64(&mut self) -> u64 { self.rng.next_u64() } + #[inline] fn fill_bytes(&mut self, dest: &mut [u8]) { self.rng.fill_bytes(dest); } + #[inline] fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { self.rng.try_fill_bytes(dest).map_err(rand_core::Error::new) } diff --git a/src/error.rs b/src/error.rs index 77525ec..8102da3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use thiserror::Error; -/// Error type for this module. +/// Error type for this crate. #[derive(Debug, Error, PartialEq)] pub enum CryptoCoreError { #[error("Wrong size: {given} given should be {expected}")] diff --git a/src/lib.rs b/src/lib.rs index 02e6fb1..b5d7df1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,26 +23,26 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub use crate::error::CryptoCoreError; pub mod reexport { - // reexport `rand_core` so that the PRNG implement the correct version of the traits + // reexport `rand_core` so that the PRNGs implement the correct version of + // the traits pub use rand_core; } -/// Trait defining a cryptographic key. +/// Cryptographic key. pub trait KeyTrait: Clone + Eq + PartialEq + Send + Sized + Sync + Zeroize + ZeroizeOnDrop { /// Key length const LENGTH: usize = LENGTH; - /// Generate a new random key. + /// Generates a new random key. #[must_use] fn new(rng: &mut R) -> Self; - /// Convert the given key into a vector of bytes. + /// Converts the given key into a vector of bytes. #[must_use] fn to_bytes(&self) -> [u8; LENGTH]; - /// Convert the given bytes into a key. An error is returned in case the - /// conversion fails. + /// Tries to convert the given bytes into a key. fn try_from_bytes(bytes: &[u8]) -> Result; } diff --git a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs index 05568a0..6c2a643 100644 --- a/src/symmetric_crypto/aes_256_gcm_pure/mod.rs +++ b/src/symmetric_crypto/aes_256_gcm_pure/mod.rs @@ -15,13 +15,13 @@ use rand_core::{CryptoRng, RngCore}; use super::{key::Key, nonce::Nonce}; -/// Use a 256-bit AES key +/// Use a 256-bit AES key. const KEY_LENGTH: usize = 32; -/// Use a 96-bit nonce +/// Use a 96-bit nonce. const NONCE_LENGTH: usize = 12; -/// Use a 128-bit MAC tag +/// Use a 128-bit MAC tag. const MAC_LENGTH: usize = 16; /// Plaintext size (in bytes) restriction from the NIST @@ -87,7 +87,7 @@ impl Dem for Aes256GcmCrypto { MAX_PLAINTEXT_LENGTH + Self::ENCRYPTION_OVERHEAD as u64 ))); } - // The ciphertext is of the form: nonce || AEAS ciphertext + // The ciphertext is of the form: nonce || AEAD ciphertext decrypt_combined( secret_key.as_bytes(), &ciphertext[Self::Nonce::LENGTH..], diff --git a/src/symmetric_crypto/key.rs b/src/symmetric_crypto/key.rs index 1852faf..b66e3ca 100644 --- a/src/symmetric_crypto/key.rs +++ b/src/symmetric_crypto/key.rs @@ -12,7 +12,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub struct Key([u8; LENGTH]); impl KeyTrait for Key { - /// Generate a new symmetric random `Key` + /// Generates a new symmetric random `Key`. #[inline] fn new(rng: &mut R) -> Self { let mut key = [0; LENGTH]; @@ -20,13 +20,13 @@ impl KeyTrait for Key { Self(key) } - /// Convert the given key into bytes. + /// Converts the given key into bytes. #[inline] fn to_bytes(&self) -> [u8; LENGTH] { self.0.to_owned() } - /// Try to convert the given bytes into a key. Size must be correct. + /// Tries to convert the given bytes into a key. Size must be correct. #[inline] fn try_from_bytes(bytes: &[u8]) -> Result { let bytes = <[u8; LENGTH]>::try_from(bytes) @@ -36,19 +36,19 @@ impl KeyTrait for Key { } impl SymKey for Key { - /// Convert the given key into a byte slice. + /// Converts the given key into a byte slice. #[inline] fn as_bytes(&self) -> &[u8] { &self.0 } - /// Consume the key to return underlying bytes. + /// Consumes the key to return underlying bytes. #[inline] fn into_bytes(self) -> [u8; LENGTH] { self.0 } - /// Convert the given bytes with correct size into a key. + /// Converts the given bytes with correct size into a key. #[inline] fn from_bytes(bytes: [u8; LENGTH]) -> Self { Self(bytes) @@ -67,7 +67,7 @@ impl Zeroize for Key { } } -// Implement `Drop` trait to follow R23. +// Implements `Drop` trait to follow R23. impl Drop for Key { fn drop(&mut self) { self.zeroize(); diff --git a/src/symmetric_crypto/metadata.rs b/src/symmetric_crypto/metadata.rs index 9e1bf2d..4412da6 100644 --- a/src/symmetric_crypto/metadata.rs +++ b/src/symmetric_crypto/metadata.rs @@ -23,12 +23,13 @@ pub struct BytesScanner<'a> { impl<'a> BytesScanner<'a> { /// Returns a new byte scanner object. #[must_use] + #[inline] pub const fn new(bytes: &'a [u8]) -> Self { BytesScanner { bytes, start: 0 } } /// Returns a slice of the next `size` bytes or an error if less is - /// available + /// available. pub fn next(&mut self, size: usize) -> Result<&'a [u8], CryptoCoreError> { let end = self.start + size; if self.bytes.len() < end { @@ -42,7 +43,7 @@ impl<'a> BytesScanner<'a> { Ok(chunk) } - /// Reads the next 4 big endian bytes to return an u32 + /// Reads the next 4 big endian bytes to return an u32. pub fn read_u32(&mut self) -> Result { Ok(u32::from_be_bytes(self.next(4)?.try_into().map_err( |_e| CryptoCoreError::ConversionError("invalid u32".to_string()), @@ -60,23 +61,24 @@ impl<'a> BytesScanner<'a> { } } - /// Return `true` if there still are some bytes to read. + /// Returns `true` if there still are some bytes to read. pub fn has_more(&self) -> bool { self.start < self.bytes.len() } } -/// Metadata encrypted as part of the header +/// Metadata encrypted as part of the header. /// /// The `uid` is a security parameter: -/// - when using a stream cipher such as AES, it uniquely -/// identifies a resource, such as a file, and is part of the AEAD of every -/// block when symmetrically encrypting data. It prevents an attacker from -/// moving blocks between resources. -/// - when using FPE, it is the "tweak" ([see Appendix C](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)) +/// - when using a stream cipher such as AES, it uniquely identifies a +/// resource, such as a file, and is part of the AEAD of every block when +/// symmetrically encrypting data. It prevents an attacker from moving +/// blocks between resources. +/// - when using FPE, it is the "tweak" +/// ([see Appendix C](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf)) /// -/// The `additional_data` is not used as a security parameter. It is optional -/// data (such as index tags) symmetrically encrypted as part of the header. +/// The `additional_data` is *not* used as a security parameter, it is an +/// optional data (such as index tags). #[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] pub struct Metadata { pub uid: Vec, @@ -84,7 +86,7 @@ pub struct Metadata { } impl Metadata { - /// The length in bytes of this meta data + /// Returns the length in bytes of this metadata. pub fn len(&self) -> usize { self.uid.len() + self.additional_data.as_ref().unwrap_or(&vec![]).len() } @@ -95,9 +97,14 @@ impl Metadata { self.len() == 0 } - /// Encode the metadata as a byte array + /// Encodes the metadata as a byte array. /// /// The first 4 bytes is the `u32` length of the UID as big endian bytes + /// + /// TODO: when LEB128 parsing is moved from CoverCrypt to an independent + /// crate, we can implement `read()` and `write()` for this object. This + /// will allows reducing the size of the serialized length saving up to 3 + /// bytes when the UID is small. pub fn try_to_bytes(&self) -> Result, CryptoCoreError> { if self.is_empty() { return Ok(vec![]); @@ -111,7 +118,9 @@ impl Metadata { Ok(bytes) } - /// Decode the metadata from a byte array + /// Decodes the metadata from a byte array. + /// + /// TODO: see `try_to_bytes()` documentation. pub fn try_from_bytes(bytes: &[u8]) -> Result { if bytes.is_empty() { return Ok(Self::default()); diff --git a/src/symmetric_crypto/mod.rs b/src/symmetric_crypto/mod.rs index 70c5bda..bccbba2 100644 --- a/src/symmetric_crypto/mod.rs +++ b/src/symmetric_crypto/mod.rs @@ -19,15 +19,15 @@ use std::vec::Vec; /// Defines a symmetric encryption key. pub trait SymKey: KeyTrait + Hash { - /// Convert the given key into a byte slice. + /// Converts the given key into a byte slice. #[must_use] fn as_bytes(&self) -> &[u8]; - /// Consume the key to return underlying bytes. + /// Consumes the key to return the underlying bytes. #[must_use] fn into_bytes(self) -> [u8; LENGTH]; - /// Convert the given bytes into a key. + /// Converts the given bytes into a key. #[must_use] fn from_bytes(bytes: [u8; LENGTH]) -> Self; } @@ -38,7 +38,7 @@ pub trait Dem: Debug + PartialEq { /// Number of bytes added to the message length in the encapsulation. const ENCRYPTION_OVERHEAD: usize = Self::Nonce::LENGTH + Self::MAC_LENGTH; - /// MAC length + /// MAC tag length const MAC_LENGTH: usize; /// Symmetric key length @@ -50,7 +50,7 @@ pub trait Dem: Debug + PartialEq { /// Associated key type type Key: SymKey; - /// Encrypt data using the given symmetric key. + /// Encrypts data using the given symmetric key. /// /// - `rng` : secure random number generator /// - `secret_key` : secret symmetric key @@ -64,7 +64,7 @@ pub trait Dem: Debug + PartialEq { aad: Option<&[u8]>, ) -> Result, CryptoCoreError>; - /// Decrypt data using the given symmetric key. + /// Decrypts data using the given symmetric key. /// /// - `secret_key` : symmetric key /// - `ciphertext` : ciphertext message diff --git a/src/symmetric_crypto/nonce.rs b/src/symmetric_crypto/nonce.rs index b0dc442..4941394 100644 --- a/src/symmetric_crypto/nonce.rs +++ b/src/symmetric_crypto/nonce.rs @@ -1,4 +1,4 @@ -//! Define a nonce object, for use in symmetric encryption. +//! Defines a nonce object, for use in symmetric encryption. //! //! A nonce, for Number used ONCE, is a randomly generated number used to //! ensure a ciphertext cannot be reused, hence avoiding replay attacks. @@ -10,24 +10,24 @@ use core::{ }; use rand_core::{CryptoRng, RngCore}; -/// Trait defining a nonce for use in a symmetric encryption scheme. +/// Defines a nonce to use in a symmetric encryption scheme. pub trait NonceTrait: Send + Sync + Sized + Clone { /// Size of the nonce in bytes. const LENGTH: usize; - /// Generate a new nonce object. + /// Generates a new nonce object. #[must_use] fn new(rng: &mut R) -> Self; - /// Try to deserialize the given `bytes` into a nonce object. The number of - /// `bytes` must be equal to `Self::LENGTH`. + /// Tries to deserialize the given `bytes` into a nonce object. The number + /// of `bytes` must be equal to `Self::LENGTH`. fn try_from_bytes(bytes: &[u8]) -> Result; /// Xor the nonce with the given value. #[must_use] fn xor(&self, b2: &[u8]) -> Self; - /// Serialize the nonce. + /// Serializes the nonce. fn as_bytes(&self) -> &[u8]; }