diff --git a/pkcs5/src/lib.rs b/pkcs5/src/lib.rs index 08993c245..f8439ad90 100644 --- a/pkcs5/src/lib.rs +++ b/pkcs5/src/lib.rs @@ -49,7 +49,7 @@ use alloc::vec::Vec; #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] -pub enum EncryptionScheme<'a> { +pub enum EncryptionScheme { /// Password-Based Encryption Scheme 1 as defined in [RFC 8018 Section 6.1]. /// /// [RFC 8018 Section 6.1]: https://tools.ietf.org/html/rfc8018#section-6.1 @@ -58,10 +58,10 @@ pub enum EncryptionScheme<'a> { /// Password-Based Encryption Scheme 2 as defined in [RFC 8018 Section 6.2]. /// /// [RFC 8018 Section 6.2]: https://tools.ietf.org/html/rfc8018#section-6.2 - Pbes2(pbes2::Parameters<'a>), + Pbes2(pbes2::Parameters), } -impl<'a> EncryptionScheme<'a> { +impl EncryptionScheme { /// Attempt to decrypt the given ciphertext, allocating and returning a /// byte vector containing the plaintext. #[cfg(all(feature = "alloc", feature = "pbes2"))] @@ -79,11 +79,11 @@ impl<'a> EncryptionScheme<'a> { /// is unsupported, or if the ciphertext is malformed (e.g. not a multiple /// of a block mode's padding) #[cfg(feature = "pbes2")] - pub fn decrypt_in_place<'b>( + pub fn decrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], - ) -> Result<&'b [u8]> { + buffer: &'a mut [u8], + ) -> Result<&'a [u8]> { match self { Self::Pbes2(params) => params.decrypt_in_place(password, buffer), Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport), @@ -103,12 +103,12 @@ impl<'a> EncryptionScheme<'a> { /// Encrypt the given ciphertext in-place using a key derived from the /// provided password and this scheme's parameters. #[cfg(feature = "pbes2")] - pub fn encrypt_in_place<'b>( + pub fn encrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], + buffer: &'a mut [u8], pos: usize, - ) -> Result<&'b [u8]> { + ) -> Result<&'a [u8]> { match self { Self::Pbes2(params) => params.encrypt_in_place(password, buffer, pos), Self::Pbes1(_) => Err(Error::NoPbes1CryptSupport), @@ -132,7 +132,7 @@ impl<'a> EncryptionScheme<'a> { } /// Get [`pbes2::Parameters`] if it is the selected algorithm. - pub fn pbes2(&self) -> Option<&pbes2::Parameters<'a>> { + pub fn pbes2(&self) -> Option<&pbes2::Parameters> { match self { Self::Pbes2(params) => Some(params), _ => None, @@ -140,13 +140,13 @@ impl<'a> EncryptionScheme<'a> { } } -impl<'a> DecodeValue<'a> for EncryptionScheme<'a> { +impl<'a> DecodeValue<'a> for EncryptionScheme { fn decode_value>(decoder: &mut R, header: Header) -> der::Result { AlgorithmIdentifierRef::decode_value(decoder, header)?.try_into() } } -impl EncodeValue for EncryptionScheme<'_> { +impl EncodeValue for EncryptionScheme { fn value_len(&self) -> der::Result { match self { Self::Pbes1(pbes1) => pbes1.oid().encoded_len()? + pbes1.parameters.encoded_len()?, @@ -170,24 +170,24 @@ impl EncodeValue for EncryptionScheme<'_> { } } -impl<'a> Sequence<'a> for EncryptionScheme<'a> {} +impl Sequence<'_> for EncryptionScheme {} -impl<'a> From for EncryptionScheme<'a> { - fn from(alg: pbes1::Algorithm) -> EncryptionScheme<'a> { +impl From for EncryptionScheme { + fn from(alg: pbes1::Algorithm) -> EncryptionScheme { Self::Pbes1(alg) } } -impl<'a> From> for EncryptionScheme<'a> { - fn from(params: pbes2::Parameters<'a>) -> EncryptionScheme<'a> { +impl From for EncryptionScheme { + fn from(params: pbes2::Parameters) -> EncryptionScheme { Self::Pbes2(params) } } -impl<'a> TryFrom> for EncryptionScheme<'a> { +impl TryFrom> for EncryptionScheme { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result> { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if alg.oid == pbes2::PBES2_OID { match alg.parameters { Some(params) => pbes2::Parameters::try_from(params).map(Into::into), @@ -199,10 +199,10 @@ impl<'a> TryFrom> for EncryptionScheme<'a> { } } -impl<'a> TryFrom<&'a [u8]> for EncryptionScheme<'a> { +impl TryFrom<&[u8]> for EncryptionScheme { type Error = der::Error; - fn try_from(bytes: &'a [u8]) -> der::Result> { + fn try_from(bytes: &[u8]) -> der::Result { AlgorithmIdentifierRef::from_der(bytes)?.try_into() } } diff --git a/pkcs5/src/pbes2.rs b/pkcs5/src/pbes2.rs index 301105cc2..095ae1ddb 100644 --- a/pkcs5/src/pbes2.rs +++ b/pkcs5/src/pbes2.rs @@ -8,7 +8,7 @@ mod kdf; mod encryption; pub use self::kdf::{ - Kdf, Pbkdf2Params, Pbkdf2Prf, ScryptParams, HMAC_WITH_SHA1_OID, HMAC_WITH_SHA256_OID, + Kdf, Pbkdf2Params, Pbkdf2Prf, Salt, ScryptParams, HMAC_WITH_SHA1_OID, HMAC_WITH_SHA256_OID, PBKDF2_OID, SCRYPT_OID, }; @@ -66,21 +66,21 @@ const DES_BLOCK_SIZE: usize = 8; /// /// [RFC 8018 Appendix A.4]: https://tools.ietf.org/html/rfc8018#appendix-A.4 #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Parameters<'a> { +pub struct Parameters { /// Key derivation function - pub kdf: Kdf<'a>, + pub kdf: Kdf, /// Encryption scheme - pub encryption: EncryptionScheme<'a>, + pub encryption: EncryptionScheme, } -impl<'a> Parameters<'a> { +impl Parameters { /// Initialize PBES2 parameters using PBKDF2-SHA256 as the password-based /// key derivation function and AES-128-CBC as the symmetric cipher. pub fn pbkdf2_sha256_aes128cbc( pbkdf2_iterations: u32, - pbkdf2_salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + pbkdf2_salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into(); let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv }; @@ -91,8 +91,8 @@ impl<'a> Parameters<'a> { /// key derivation function and AES-256-CBC as the symmetric cipher. pub fn pbkdf2_sha256_aes256cbc( pbkdf2_iterations: u32, - pbkdf2_salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + pbkdf2_salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = Pbkdf2Params::hmac_with_sha256(pbkdf2_iterations, pbkdf2_salt)?.into(); let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv }; @@ -108,8 +108,8 @@ impl<'a> Parameters<'a> { #[cfg(feature = "pbes2")] pub fn scrypt_aes128cbc( params: scrypt::Params, - salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = ScryptParams::from_params_and_salt(params, salt)?.into(); let encryption = EncryptionScheme::Aes128Cbc { iv: aes_iv }; @@ -128,8 +128,8 @@ impl<'a> Parameters<'a> { #[cfg(feature = "pbes2")] pub fn scrypt_aes256cbc( params: scrypt::Params, - salt: &'a [u8], - aes_iv: &'a [u8; AES_BLOCK_SIZE], + salt: &[u8], + aes_iv: [u8; AES_BLOCK_SIZE], ) -> Result { let kdf = ScryptParams::from_params_and_salt(params, salt)?.into(); let encryption = EncryptionScheme::Aes256Cbc { iv: aes_iv }; @@ -153,11 +153,11 @@ impl<'a> Parameters<'a> { /// is unsupported, or if the ciphertext is malformed (e.g. not a multiple /// of a block mode's padding) #[cfg(feature = "pbes2")] - pub fn decrypt_in_place<'b>( + pub fn decrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], - ) -> Result<&'b [u8]> { + buffer: &'a mut [u8], + ) -> Result<&'a [u8]> { encryption::decrypt_in_place(self, password, buffer) } @@ -182,23 +182,23 @@ impl<'a> Parameters<'a> { /// provided password and this scheme's parameters, writing the ciphertext /// into the same buffer. #[cfg(feature = "pbes2")] - pub fn encrypt_in_place<'b>( + pub fn encrypt_in_place<'a>( &self, password: impl AsRef<[u8]>, - buffer: &'b mut [u8], + buffer: &'a mut [u8], pos: usize, - ) -> Result<&'b [u8]> { + ) -> Result<&'a [u8]> { encryption::encrypt_in_place(self, password, buffer, pos) } } -impl<'a> DecodeValue<'a> for Parameters<'a> { +impl<'a> DecodeValue<'a> for Parameters { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Parameters<'_> { +impl EncodeValue for Parameters { fn value_len(&self) -> der::Result { self.kdf.encoded_len()? + self.encryption.encoded_len()? } @@ -210,12 +210,12 @@ impl EncodeValue for Parameters<'_> { } } -impl<'a> Sequence<'a> for Parameters<'a> {} +impl Sequence<'_> for Parameters {} -impl<'a> TryFrom> for Parameters<'a> { +impl TryFrom> for Parameters { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|params| { let kdf = AlgorithmIdentifierRef::decode(params)?; let encryption = AlgorithmIdentifierRef::decode(params)?; @@ -231,41 +231,41 @@ impl<'a> TryFrom> for Parameters<'a> { /// Symmetric encryption scheme used by PBES2. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum EncryptionScheme<'a> { +pub enum EncryptionScheme { /// AES-128 in CBC mode Aes128Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// AES-192 in CBC mode Aes192Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// AES-256 in CBC mode Aes256Cbc { /// Initialization vector - iv: &'a [u8; AES_BLOCK_SIZE], + iv: [u8; AES_BLOCK_SIZE], }, /// 3-Key Triple DES in CBC mode #[cfg(feature = "3des")] DesEde3Cbc { /// Initialisation vector - iv: &'a [u8; DES_BLOCK_SIZE], + iv: [u8; DES_BLOCK_SIZE], }, /// DES in CBC mode #[cfg(feature = "des-insecure")] DesCbc { /// Initialisation vector - iv: &'a [u8; DES_BLOCK_SIZE], + iv: [u8; DES_BLOCK_SIZE], }, } -impl<'a> EncryptionScheme<'a> { +impl EncryptionScheme { /// Get the size of a key used by this algorithm in bytes. pub fn key_size(&self) -> usize { match self { @@ -300,19 +300,19 @@ impl<'a> EncryptionScheme<'a> { } } -impl<'a> Decode<'a> for EncryptionScheme<'a> { +impl<'a> Decode<'a> for EncryptionScheme { fn decode>(reader: &mut R) -> der::Result { AlgorithmIdentifierRef::decode(reader).and_then(TryInto::try_into) } } -impl<'a> TryFrom> for EncryptionScheme<'a> { +impl TryFrom> for EncryptionScheme { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { // TODO(tarcieri): support for non-AES algorithms? let iv = match alg.parameters { - Some(params) => params.decode_as::>()?.as_bytes(), + Some(params) => params.decode_as::>()?.as_bytes(), None => return Err(Tag::OctetString.value_error()), }; @@ -349,18 +349,18 @@ impl<'a> TryFrom> for EncryptionScheme<'a> { } } -impl<'a> TryFrom> for AlgorithmIdentifierRef<'a> { +impl<'a> TryFrom<&'a EncryptionScheme> for AlgorithmIdentifierRef<'a> { type Error = der::Error; - fn try_from(scheme: EncryptionScheme<'a>) -> der::Result { + fn try_from(scheme: &'a EncryptionScheme) -> der::Result { let parameters = OctetStringRef::new(match scheme { - EncryptionScheme::Aes128Cbc { iv } => iv, - EncryptionScheme::Aes192Cbc { iv } => iv, - EncryptionScheme::Aes256Cbc { iv } => iv, + EncryptionScheme::Aes128Cbc { iv } => iv.as_slice(), + EncryptionScheme::Aes192Cbc { iv } => iv.as_slice(), + EncryptionScheme::Aes256Cbc { iv } => iv.as_slice(), #[cfg(feature = "des-insecure")] - EncryptionScheme::DesCbc { iv } => iv, + EncryptionScheme::DesCbc { iv } => iv.as_slice(), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => iv, + EncryptionScheme::DesEde3Cbc { iv } => iv.as_slice(), })?; Ok(AlgorithmIdentifierRef { @@ -370,12 +370,12 @@ impl<'a> TryFrom> for AlgorithmIdentifierRef<'a> { } } -impl<'a> Encode for EncryptionScheme<'a> { +impl Encode for EncryptionScheme { fn encoded_len(&self) -> der::Result { - AlgorithmIdentifierRef::try_from(*self)?.encoded_len() + AlgorithmIdentifierRef::try_from(self)?.encoded_len() } fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { - AlgorithmIdentifierRef::try_from(*self)?.encode(writer) + AlgorithmIdentifierRef::try_from(self)?.encode(writer) } } diff --git a/pkcs5/src/pbes2/encryption.rs b/pkcs5/src/pbes2/encryption.rs index ea029b66a..86349926d 100644 --- a/pkcs5/src/pbes2/encryption.rs +++ b/pkcs5/src/pbes2/encryption.rs @@ -20,7 +20,7 @@ use scrypt::scrypt; const MAX_KEY_LEN: usize = 32; fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>( - es: EncryptionScheme<'_>, + es: EncryptionScheme, key: EncryptionKey, iv: &[u8], buffer: &'a mut [u8], @@ -33,7 +33,7 @@ fn cbc_encrypt<'a, C: BlockEncryptMut + BlockCipher + KeyInit>( } fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>( - es: EncryptionScheme<'_>, + es: EncryptionScheme, key: EncryptionKey, iv: &[u8], buffer: &'a mut [u8], @@ -45,7 +45,7 @@ fn cbc_decrypt<'a, C: BlockDecryptMut + BlockCipher + KeyInit>( } pub fn encrypt_in_place<'b>( - params: &Parameters<'_>, + params: &Parameters, password: impl AsRef<[u8]>, buf: &'b mut [u8], pos: usize, @@ -58,11 +58,11 @@ pub fn encrypt_in_place<'b>( let key = EncryptionKey::derive_from_password(password.as_ref(), ¶ms.kdf, key_size)?; match es { - EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), - EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), - EncryptionScheme::Aes256Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), + EncryptionScheme::Aes128Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), + EncryptionScheme::Aes192Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), + EncryptionScheme::Aes256Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => cbc_encrypt::(es, key, iv, buf, pos), + EncryptionScheme::DesEde3Cbc { iv } => cbc_encrypt::(es, key, &iv, buf, pos), #[cfg(feature = "des-insecure")] EncryptionScheme::DesCbc { .. } => Err(Error::UnsupportedAlgorithm { oid: super::DES_CBC_OID, @@ -72,7 +72,7 @@ pub fn encrypt_in_place<'b>( /// Decrypt a message encrypted with PBES2-based key derivation pub fn decrypt_in_place<'a>( - params: &Parameters<'_>, + params: &Parameters, password: impl AsRef<[u8]>, buf: &'a mut [u8], ) -> Result<&'a [u8]> { @@ -80,13 +80,13 @@ pub fn decrypt_in_place<'a>( let key = EncryptionKey::derive_from_password(password.as_ref(), ¶ms.kdf, es.key_size())?; match es { - EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::(es, key, iv, buf), - EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::(es, key, iv, buf), - EncryptionScheme::Aes256Cbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::Aes128Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), + EncryptionScheme::Aes192Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), + EncryptionScheme::Aes256Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), #[cfg(feature = "3des")] - EncryptionScheme::DesEde3Cbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::DesEde3Cbc { iv } => cbc_decrypt::(es, key, &iv, buf), #[cfg(feature = "des-insecure")] - EncryptionScheme::DesCbc { iv } => cbc_decrypt::(es, key, iv, buf), + EncryptionScheme::DesCbc { iv } => cbc_decrypt::(es, key, &iv, buf), } } @@ -99,7 +99,7 @@ struct EncryptionKey { impl EncryptionKey { /// Derive an encryption key using the supplied PBKDF parameters. - pub fn derive_from_password(password: &[u8], kdf: &Kdf<'_>, key_size: usize) -> Result { + pub fn derive_from_password(password: &[u8], kdf: &Kdf, key_size: usize) -> Result { // if the kdf params defined a key length, ensure it matches the required key size if let Some(len) = kdf.key_length() { if key_size != len.into() { @@ -153,7 +153,7 @@ impl EncryptionKey { } /// Derive key using PBKDF2. - fn derive_with_pbkdf2(password: &[u8], params: &Pbkdf2Params<'_>, length: usize) -> Self + fn derive_with_pbkdf2(password: &[u8], params: &Pbkdf2Params, length: usize) -> Self where D: CoreProxy, D::Core: Sync @@ -170,7 +170,7 @@ impl EncryptionKey { pbkdf2_hmac::( password, - params.salt, + params.salt.as_ref(), params.iteration_count, &mut buffer[..length], ); @@ -179,15 +179,11 @@ impl EncryptionKey { } /// Derive key using scrypt. - fn derive_with_scrypt( - password: &[u8], - params: &ScryptParams<'_>, - length: usize, - ) -> Result { + fn derive_with_scrypt(password: &[u8], params: &ScryptParams, length: usize) -> Result { let mut buffer = [0u8; MAX_KEY_LEN]; scrypt( password, - params.salt, + params.salt.as_ref(), ¶ms.try_into()?, &mut buffer[..length], ) diff --git a/pkcs5/src/pbes2/kdf.rs b/pkcs5/src/pbes2/kdf.rs index 63378cbcb..b16496351 100644 --- a/pkcs5/src/pbes2/kdf.rs +++ b/pkcs5/src/pbes2/kdf.rs @@ -1,8 +1,12 @@ //! Key derivation functions. +mod salt; + +pub use self::salt::Salt; + use crate::{AlgorithmIdentifierRef, Error, Result}; use der::{ - asn1::{AnyRef, ObjectIdentifier, OctetStringRef}, + asn1::{AnyRef, ObjectIdentifier}, Decode, DecodeValue, Encode, EncodeValue, ErrorKind, Length, Reader, Sequence, Tag, Tagged, Writer, }; @@ -40,15 +44,15 @@ type ScryptCost = u64; /// Password-based key derivation function. #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] -pub enum Kdf<'a> { +pub enum Kdf { /// Password-Based Key Derivation Function 2 (PBKDF2). - Pbkdf2(Pbkdf2Params<'a>), + Pbkdf2(Pbkdf2Params), /// scrypt sequential memory-hard password hashing function. - Scrypt(ScryptParams<'a>), + Scrypt(ScryptParams), } -impl<'a> Kdf<'a> { +impl Kdf { /// Get derived key length in bytes, if defined. // TODO(tarcieri): rename to `key_size` to match `EncryptionScheme::key_size`? pub fn key_length(&self) -> Option { @@ -67,7 +71,7 @@ impl<'a> Kdf<'a> { } /// Get [`Pbkdf2Params`] if it is the selected algorithm. - pub fn pbkdf2(&self) -> Option<&Pbkdf2Params<'a>> { + pub fn pbkdf2(&self) -> Option<&Pbkdf2Params> { match self { Self::Pbkdf2(params) => Some(params), _ => None, @@ -75,7 +79,7 @@ impl<'a> Kdf<'a> { } /// Get [`ScryptParams`] if it is the selected algorithm. - pub fn scrypt(&self) -> Option<&ScryptParams<'a>> { + pub fn scrypt(&self) -> Option<&ScryptParams> { match self { Self::Scrypt(params) => Some(params), _ => None, @@ -99,13 +103,13 @@ impl<'a> Kdf<'a> { } } -impl<'a> DecodeValue<'a> for Kdf<'a> { +impl<'a> DecodeValue<'a> for Kdf { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AlgorithmIdentifierRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Kdf<'_> { +impl EncodeValue for Kdf { fn value_len(&self) -> der::Result { self.oid().encoded_len()? + match self { @@ -126,24 +130,24 @@ impl EncodeValue for Kdf<'_> { } } -impl<'a> Sequence<'a> for Kdf<'a> {} +impl Sequence<'_> for Kdf {} -impl<'a> From> for Kdf<'a> { - fn from(params: Pbkdf2Params<'a>) -> Self { +impl From for Kdf { + fn from(params: Pbkdf2Params) -> Self { Kdf::Pbkdf2(params) } } -impl<'a> From> for Kdf<'a> { - fn from(params: ScryptParams<'a>) -> Self { +impl From for Kdf { + fn from(params: ScryptParams) -> Self { Kdf::Scrypt(params) } } -impl<'a> TryFrom> for Kdf<'a> { +impl TryFrom> for Kdf { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if let Some(params) = alg.parameters { match alg.oid { PBKDF2_OID => params.try_into().map(Self::Pbkdf2), @@ -172,11 +176,11 @@ impl<'a> TryFrom> for Kdf<'a> { /// ``` /// /// [RFC 8018 Appendix A.2]: https://tools.ietf.org/html/rfc8018#appendix-A.2 -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Pbkdf2Params<'a> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Pbkdf2Params { /// PBKDF2 salt // TODO(tarcieri): support `CHOICE` with `otherSource` - pub salt: &'a [u8], + pub salt: Salt, /// PBKDF2 iteration count pub iteration_count: u32, @@ -188,7 +192,7 @@ pub struct Pbkdf2Params<'a> { pub prf: Pbkdf2Prf, } -impl<'a> Pbkdf2Params<'a> { +impl Pbkdf2Params { /// Implementation defined maximum iteration count of 100,000,000. /// /// > For especially critical keys, or @@ -203,12 +207,13 @@ impl<'a> Pbkdf2Params<'a> { const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: PBKDF2_OID }; /// Initialize PBKDF2-SHA256 with the given iteration count and salt - pub fn hmac_with_sha256(iteration_count: u32, salt: &'a [u8]) -> Result { + pub fn hmac_with_sha256(iteration_count: u32, salt: &[u8]) -> Result { if iteration_count > Self::MAX_ITERATION_COUNT { return Err(Self::INVALID_ERR); } + Ok(Self { - salt, + salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?, iteration_count, key_length: None, prf: Pbkdf2Prf::HmacWithSha256, @@ -216,15 +221,15 @@ impl<'a> Pbkdf2Params<'a> { } } -impl<'a> DecodeValue<'a> for Pbkdf2Params<'a> { +impl<'a> DecodeValue<'a> for Pbkdf2Params { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for Pbkdf2Params<'_> { +impl EncodeValue for Pbkdf2Params { fn value_len(&self) -> der::Result { - let len = OctetStringRef::new(self.salt)?.encoded_len()? + let len = self.salt.encoded_len()? + self.iteration_count.encoded_len()? + self.key_length.encoded_len()?; @@ -236,7 +241,7 @@ impl EncodeValue for Pbkdf2Params<'_> { } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - OctetStringRef::new(self.salt)?.encode(writer)?; + self.salt.encode(writer)?; self.iteration_count.encode(writer)?; self.key_length.encode(writer)?; @@ -248,16 +253,16 @@ impl EncodeValue for Pbkdf2Params<'_> { } } -impl<'a> Sequence<'a> for Pbkdf2Params<'a> {} +impl Sequence<'_> for Pbkdf2Params {} -impl<'a> TryFrom> for Pbkdf2Params<'a> { +impl TryFrom> for Pbkdf2Params { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|reader| { // TODO(tarcieri): support salt `CHOICE` w\ `AlgorithmIdentifier` Ok(Self { - salt: OctetStringRef::decode(reader)?.as_bytes(), + salt: reader.decode()?, iteration_count: reader.decode()?, key_length: reader.decode()?, prf: Option::>::decode(reader)? @@ -316,10 +321,10 @@ impl Default for Pbkdf2Prf { } } -impl<'a> TryFrom> for Pbkdf2Prf { +impl TryFrom> for Pbkdf2Prf { type Error = der::Error; - fn try_from(alg: AlgorithmIdentifierRef<'a>) -> der::Result { + fn try_from(alg: AlgorithmIdentifierRef<'_>) -> der::Result { if let Some(params) = alg.parameters { // TODO(tarcieri): support non-NULL parameters? if !params.is_null() { @@ -341,7 +346,7 @@ impl<'a> TryFrom> for Pbkdf2Prf { } } -impl<'a> From for AlgorithmIdentifierRef<'a> { +impl From for AlgorithmIdentifierRef<'_> { fn from(prf: Pbkdf2Prf) -> Self { // TODO(tarcieri): support non-NULL parameters? let parameters = der::asn1::Null; @@ -376,10 +381,10 @@ impl Encode for Pbkdf2Prf { /// ``` /// /// [RFC 7914 Section 7.1]: https://datatracker.ietf.org/doc/html/rfc7914#section-7.1 -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct ScryptParams<'a> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ScryptParams { /// scrypt salt - pub salt: &'a [u8], + pub salt: Salt, /// CPU/Memory cost parameter `N`. pub cost_parameter: ScryptCost, @@ -394,7 +399,7 @@ pub struct ScryptParams<'a> { pub key_length: Option, } -impl<'a> ScryptParams<'a> { +impl ScryptParams { #[cfg(feature = "pbes2")] const INVALID_ERR: Error = Error::AlgorithmParametersInvalid { oid: SCRYPT_OID }; @@ -402,9 +407,9 @@ impl<'a> ScryptParams<'a> { /// and a provided salt string. // TODO(tarcieri): encapsulate `scrypt::Params`? #[cfg(feature = "pbes2")] - pub fn from_params_and_salt(params: scrypt::Params, salt: &'a [u8]) -> Result { + pub fn from_params_and_salt(params: scrypt::Params, salt: &[u8]) -> Result { Ok(Self { - salt, + salt: salt.try_into().map_err(|_| Self::INVALID_ERR)?, cost_parameter: 1 << params.log_n(), block_size: params.r().try_into().map_err(|_| Self::INVALID_ERR)?, parallelization: params.p().try_into().map_err(|_| Self::INVALID_ERR)?, @@ -413,15 +418,15 @@ impl<'a> ScryptParams<'a> { } } -impl<'a> DecodeValue<'a> for ScryptParams<'a> { +impl<'a> DecodeValue<'a> for ScryptParams { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { AnyRef::decode_value(reader, header)?.try_into() } } -impl EncodeValue for ScryptParams<'_> { +impl EncodeValue for ScryptParams { fn value_len(&self) -> der::Result { - OctetStringRef::new(self.salt)?.encoded_len()? + self.salt.encoded_len()? + self.cost_parameter.encoded_len()? + self.block_size.encoded_len()? + self.parallelization.encoded_len()? @@ -429,7 +434,7 @@ impl EncodeValue for ScryptParams<'_> { } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { - OctetStringRef::new(self.salt)?.encode(writer)?; + self.salt.encode(writer)?; self.cost_parameter.encode(writer)?; self.block_size.encode(writer)?; self.parallelization.encode(writer)?; @@ -438,15 +443,15 @@ impl EncodeValue for ScryptParams<'_> { } } -impl<'a> Sequence<'a> for ScryptParams<'a> {} +impl Sequence<'_> for ScryptParams {} -impl<'a> TryFrom> for ScryptParams<'a> { +impl TryFrom> for ScryptParams { type Error = der::Error; - fn try_from(any: AnyRef<'a>) -> der::Result { + fn try_from(any: AnyRef<'_>) -> der::Result { any.sequence(|reader| { Ok(Self { - salt: OctetStringRef::decode(reader)?.as_bytes(), + salt: reader.decode()?, cost_parameter: reader.decode()?, block_size: reader.decode()?, parallelization: reader.decode()?, @@ -457,19 +462,19 @@ impl<'a> TryFrom> for ScryptParams<'a> { } #[cfg(feature = "pbes2")] -impl<'a> TryFrom> for scrypt::Params { +impl TryFrom for scrypt::Params { type Error = Error; - fn try_from(params: ScryptParams<'a>) -> Result { + fn try_from(params: ScryptParams) -> Result { scrypt::Params::try_from(¶ms) } } #[cfg(feature = "pbes2")] -impl<'a> TryFrom<&ScryptParams<'a>> for scrypt::Params { +impl TryFrom<&ScryptParams> for scrypt::Params { type Error = Error; - fn try_from(params: &ScryptParams<'a>) -> Result { + fn try_from(params: &ScryptParams) -> Result { let n = params.cost_parameter; // Compute log2 and verify its correctness diff --git a/pkcs5/src/pbes2/kdf/salt.rs b/pkcs5/src/pbes2/kdf/salt.rs new file mode 100644 index 000000000..75c5a0758 --- /dev/null +++ b/pkcs5/src/pbes2/kdf/salt.rs @@ -0,0 +1,102 @@ +//! Salt storage buffer which works on heapless `no_std` targets. +// TODO(tarcieri): use `ArrayVec` when it's available in `core`. + +use core::fmt; +use der::{DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Writer}; + +/// Salt as used by the PBES2 KDF. +#[derive(Clone, Eq, PartialEq)] +pub struct Salt { + inner: [u8; Self::MAX_LEN], + length: Length, +} + +impl Salt { + /// Maximum length of a salt that can be stored. + pub const MAX_LEN: usize = 32; + + /// Create a new salt from the given byte slice. + pub fn new(slice: impl AsRef<[u8]>) -> Result { + let slice = slice.as_ref(); + + if slice.len() > Self::MAX_LEN { + return Err(Self::TAG.length_error()); + } + + let mut inner = [0u8; Self::MAX_LEN]; + let mut i = 0; + + while i < slice.len() { + inner[i] = slice[i]; + i += 1; + } + + Ok(Self { + inner, + length: Length::new(slice.len() as u16), + }) + } + + /// Borrow the salt data as a byte slice. + pub fn as_bytes(&self) -> &[u8] { + let length = usize::try_from(self.length).expect("should be less than Self::MAX_LEN"); + &self.inner[..length] + } + + /// Get the length of the salt data. + pub fn len(&self) -> Length { + self.length + } +} + +impl AsRef<[u8]> for Salt { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> DecodeValue<'a> for Salt { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let length = usize::try_from(header.length)?; + + if length > Self::MAX_LEN { + return Err(Self::TAG.length_error()); + } + + let mut inner = [0u8; Self::MAX_LEN]; + reader.read_into(&mut inner[..length])?; + + Ok(Self { + inner, + length: header.length, + }) + } +} + +impl EncodeValue for Salt { + fn value_len(&self) -> Result { + Ok(self.length) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + writer.write(self.as_bytes()) + } +} + +impl FixedTag for Salt { + const TAG: Tag = Tag::OctetString; +} + +impl TryFrom<&[u8]> for Salt { + type Error = Error; + + fn try_from(slice: &[u8]) -> Result { + Self::new(slice) + } +} + +impl fmt::Debug for Salt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Salt").field(&self.as_bytes()).finish() + } +} diff --git a/pkcs5/tests/pbes2.rs b/pkcs5/tests/pbes2.rs index bb280d031..53a463881 100644 --- a/pkcs5/tests/pbes2.rs +++ b/pkcs5/tests/pbes2.rs @@ -63,14 +63,14 @@ fn decode_pbes2_pbkdf2_sha1_aes128cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("e8765e01e43b6bad")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("e8765e01e43b6bad")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha1); match params.encryption { pbes2::EncryptionScheme::Aes128Cbc { iv } => { - assert_eq!(iv, &hex!("223080a71bcd2b9a256d876c924979d2")); + assert_eq!(iv, hex!("223080a71bcd2b9a256d876c924979d2")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -83,14 +83,14 @@ fn decode_pbes2_pbkdf2_sha256_aes256cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("79d982e70df91a88")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("79d982e70df91a88")); assert_eq!(pbkdf2_params.iteration_count, 2048); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); match params.encryption { pbes2::EncryptionScheme::Aes256Cbc { iv } => { - assert_eq!(iv, &hex!("b2d02d78b2efd9dff694cf8e0af40925")); + assert_eq!(iv, hex!("b2d02d78b2efd9dff694cf8e0af40925")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -103,7 +103,7 @@ fn decode_pbes2_scrypt_aes256cbc() { let params = scheme.pbes2().unwrap(); let scrypt_params = params.kdf.scrypt().unwrap(); - assert_eq!(scrypt_params.salt, &hex!("E6211E2348AD69E0")); + assert_eq!(scrypt_params.salt.as_bytes(), &hex!("E6211E2348AD69E0")); assert_eq!(scrypt_params.cost_parameter, 16384); assert_eq!(scrypt_params.block_size, 8); assert_eq!(scrypt_params.parallelization, 1); @@ -111,7 +111,7 @@ fn decode_pbes2_scrypt_aes256cbc() { match params.encryption { pbes2::EncryptionScheme::Aes256Cbc { iv } => { - assert_eq!(iv, &hex!("9BD0A6251F2254F9FD5963887C27CF01")); + assert_eq!(iv, hex!("9BD0A6251F2254F9FD5963887C27CF01")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -125,14 +125,14 @@ fn decode_pbes2_pbkdf2_sha256_desede3cbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("32A0AE2E01BBE329")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("32A0AE2E01BBE329")); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); assert_eq!(pbkdf2_params.iteration_count, 2048); match params.encryption { pbes2::EncryptionScheme::DesEde3Cbc { iv } => { - assert_eq!(iv, &hex!("97E8F53AB0ACA359")); + assert_eq!(iv, hex!("97E8F53AB0ACA359")); } other => panic!("unexpected encryption scheme: {:?}", other), } @@ -146,14 +146,14 @@ fn decode_pbes2_pbkdf2_sha256_descbc() { let params = scheme.pbes2().unwrap(); let pbkdf2_params = params.kdf.pbkdf2().unwrap(); - assert_eq!(pbkdf2_params.salt, &hex!("09E7EDFBD9F21E2B")); + assert_eq!(pbkdf2_params.salt.as_bytes(), &hex!("09E7EDFBD9F21E2B")); assert_eq!(pbkdf2_params.key_length, None); assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); assert_eq!(pbkdf2_params.iteration_count, 2048); match params.encryption { pbes2::EncryptionScheme::DesCbc { iv } => { - assert_eq!(iv, &hex!("F4AAF206A18DE7AD")); + assert_eq!(iv, hex!("F4AAF206A18DE7AD")); } other => panic!("unexpected encryption scheme: {:?}", other), }