From 0adffb74160425e018317c20688146f397693dc0 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Wed, 14 Jun 2023 09:59:05 -0700 Subject: [PATCH] CBC/CTR API Improvements --- aws-lc-rs/benches/cipher_benchmark.rs | 18 +- aws-lc-rs/examples/cipher.rs | 56 ++-- aws-lc-rs/src/cipher.rs | 379 ++++++++++++-------------- aws-lc-rs/tests/cipher_test.rs | 88 +++--- 4 files changed, 243 insertions(+), 298 deletions(-) diff --git a/aws-lc-rs/benches/cipher_benchmark.rs b/aws-lc-rs/benches/cipher_benchmark.rs index ee9d1075c04..63242445f99 100644 --- a/aws-lc-rs/benches/cipher_benchmark.rs +++ b/aws-lc-rs/benches/cipher_benchmark.rs @@ -35,25 +35,23 @@ macro_rules! benchmark_padded { CipherContext::Iv128(iv.as_slice().try_into().unwrap()); let encrypt_key = match $mode { - OperatingMode::CBC => { - PaddedBlockEncryptingKey::less_safe_cbc_pkcs7(key, iv) - } + OperatingMode::CBC => PaddedBlockEncryptingKey::cbc_pkcs7(key), _ => unreachable!(), } .unwrap(); let mut in_out = Vec::from(data.as_slice()); - let context = encrypt_key.encrypt(&mut in_out).unwrap(); + let context = encrypt_key.less_safe_encrypt(&mut in_out, iv).unwrap(); let key = UnboundCipherKey::new($awslc, &key_bytes).unwrap(); let decrypt_key = match $mode { - OperatingMode::CBC => PaddedBlockDecryptingKey::cbc_pkcs7(key, context), + OperatingMode::CBC => PaddedBlockDecryptingKey::cbc_pkcs7(key), _ => unreachable!(), } .unwrap(); - let _ = decrypt_key.decrypt(&mut in_out).unwrap(); + let _ = decrypt_key.decrypt(&mut in_out, context).unwrap(); }) }); @@ -82,23 +80,23 @@ macro_rules! benchmark_unpadded { CipherContext::Iv128(iv.as_slice().try_into().unwrap()); let encrypt_key = match $mode { - OperatingMode::CTR => EncryptingKey::less_safe_ctr(key, iv), + OperatingMode::CTR => EncryptingKey::ctr(key), _ => unreachable!(), } .unwrap(); let mut in_out = Vec::from(data.as_slice()); - let context = encrypt_key.encrypt(&mut in_out).unwrap(); + let context = encrypt_key.less_safe_encrypt(&mut in_out, iv).unwrap(); let key = UnboundCipherKey::new($awslc, &key_bytes).unwrap(); let decrypt_key = match $mode { - OperatingMode::CTR => DecryptingKey::ctr(key, context), + OperatingMode::CTR => DecryptingKey::ctr(key), _ => unreachable!(), } .unwrap(); - let _ = decrypt_key.decrypt(&mut in_out).unwrap(); + let _ = decrypt_key.decrypt(&mut in_out, context).unwrap(); }) }); diff --git a/aws-lc-rs/examples/cipher.rs b/aws-lc-rs/examples/cipher.rs index df7a80627d4..9554b7dd5ec 100644 --- a/aws-lc-rs/examples/cipher.rs +++ b/aws-lc-rs/examples/cipher.rs @@ -101,24 +101,22 @@ fn aes_ctr_encrypt(key: &[u8], iv: Option, plaintext: String) -> Result< let hex_key = hex::encode(key); let key = new_unbound_key(key)?; - let key = match iv { + let key = EncryptingKey::ctr(key).map_err(|_| "failed to initalized aes encryption")?; + + let mut ciphertext = Vec::from(plaintext); + + let context = match iv { Some(iv) => { - let iv = { + let context = { let v = hex::decode(iv).map_err(|_| "invalid iv")?; let v: FixedLength<16> = v.as_slice().try_into().map_err(|_| "invalid iv")?; - v + CipherContext::Iv128(v) }; - EncryptingKey::less_safe_ctr(key, CipherContext::Iv128(iv)) + key.less_safe_encrypt(ciphertext.as_mut(), context) } - None => EncryptingKey::ctr(key), + None => key.encrypt(ciphertext.as_mut()), } - .map_err(|_| "failed to initialized aes encryption")?; - - let mut ciphertext = Vec::from(plaintext); - - let context = key - .encrypt(ciphertext.as_mut()) - .map_err(|_| "Failed to encrypt plaintext")?; + .map_err(|_| "failed to encrypt plaintext")?; let iv: &[u8] = (&context) .try_into() @@ -141,14 +139,13 @@ fn aes_ctr_decrypt(key: &[u8], iv: String, ciphertext: String) -> Result<(), &'s v }; - let key = DecryptingKey::ctr(key, CipherContext::Iv128(iv)) - .map_err(|_| "failed to initialized aes decryption")?; + let key = DecryptingKey::ctr(key).map_err(|_| "failed to initalized aes decryption")?; let mut ciphertext = hex::decode(ciphertext).map_err(|_| "ciphertext is not valid hex encoding")?; let plaintext = key - .decrypt(ciphertext.as_mut()) + .decrypt(ciphertext.as_mut(), CipherContext::Iv128(iv)) .map_err(|_| "failed to decrypt ciphertext")?; let plaintext = @@ -163,25 +160,24 @@ fn aes_cbc_encrypt(key: &[u8], iv: Option, plaintext: String) -> Result< let hex_key = hex::encode(key); let key = new_unbound_key(key)?; - let key = match iv { + let key = PaddedBlockEncryptingKey::cbc_pkcs7(key) + .map_err(|_| "failed to initalized aes encryption")?; + + let mut ciphertext = Vec::from(plaintext); + + let context = match iv { Some(iv) => { - let iv = { + let context = { let v = hex::decode(iv).map_err(|_| "invalid iv")?; let v: FixedLength = v.as_slice().try_into().map_err(|_| "invalid iv")?; - v + CipherContext::Iv128(v) }; - PaddedBlockEncryptingKey::less_safe_cbc_pkcs7(key, CipherContext::Iv128(iv)) + key.less_safe_encrypt(&mut ciphertext, context) } - None => PaddedBlockEncryptingKey::cbc_pkcs7(key), + None => key.encrypt(&mut ciphertext), } - .map_err(|_| "failed to initialized aes encryption")?; - - let mut ciphertext = Vec::from(plaintext); - - let context = key - .encrypt(&mut ciphertext) - .map_err(|_| "Failed to encrypt plaintext")?; + .map_err(|_| "failed to initalized aes encryption")?; let iv: &[u8] = (&context) .try_into() @@ -204,14 +200,14 @@ fn aes_cbc_decrypt(key: &[u8], iv: String, ciphertext: String) -> Result<(), &'s v }; - let key = PaddedBlockDecryptingKey::cbc_pkcs7(key, CipherContext::Iv128(iv)) - .map_err(|_| "failed to initialized aes decryption")?; + let key = PaddedBlockDecryptingKey::cbc_pkcs7(key) + .map_err(|_| "failed to initalized aes decryption")?; let mut ciphertext = hex::decode(ciphertext).map_err(|_| "ciphertext is not valid hex encoding")?; let plaintext = key - .decrypt(ciphertext.as_mut()) + .decrypt(ciphertext.as_mut(), CipherContext::Iv128(iv)) .map_err(|_| "failed to decrypt ciphertext")?; let plaintext = diff --git a/aws-lc-rs/src/cipher.rs b/aws-lc-rs/src/cipher.rs index e8770339751..4a30eb18969 100644 --- a/aws-lc-rs/src/cipher.rs +++ b/aws-lc-rs/src/cipher.rs @@ -39,12 +39,12 @@ //! ]; //! //! let key = UnboundCipherKey::new(&AES_128, key_bytes)?; -//! let encrypting_key = PaddedBlockEncryptingKey::cbc_pkcs7(key)?; +//! let mut encrypting_key = PaddedBlockEncryptingKey::cbc_pkcs7(key)?; //! let context = encrypting_key.encrypt(&mut in_out_buffer)?; //! //! let key = UnboundCipherKey::new(&AES_128, key_bytes)?; -//! let decrypting_key = PaddedBlockDecryptingKey::cbc_pkcs7(key, context)?; -//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer)?; +//! let mut decrypting_key = PaddedBlockDecryptingKey::cbc_pkcs7(key)?; +//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?; //! assert_eq!(original_message, plaintext); //! # //! # @@ -69,12 +69,12 @@ //! ]; //! //! let key = UnboundCipherKey::new(&AES_128, key_bytes)?; -//! let encrypting_key = EncryptingKey::ctr(key)?; +//! let mut encrypting_key = EncryptingKey::ctr(key)?; //! let context = encrypting_key.encrypt(&mut in_out_buffer)?; //! //! let key = UnboundCipherKey::new(&AES_128, key_bytes)?; -//! let decrypting_key = DecryptingKey::ctr(key, context)?; -//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer)?; +//! let mut decrypting_key = DecryptingKey::ctr(key)?; +//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?; //! assert_eq!(original_message, plaintext); //! # //! # Ok(()) @@ -102,7 +102,7 @@ use zeroize::Zeroize; /// The cipher block padding strategy. #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum PaddingStrategy { +enum PaddingStrategy { /// PKCS#7 Padding. ([See RFC 5652](https://datatracker.ietf.org/doc/html/rfc5652#section-6.3)) PKCS7, } @@ -216,8 +216,8 @@ pub enum OperatingMode { /// 0x43, 0x29, /// ], /// )?; -/// let decrypting_key = DecryptingKey::ctr(key, context)?; -/// let plaintext = decrypting_key.decrypt(&mut in_out_buffer)?; +/// let mut decrypting_key = DecryptingKey::ctr(key)?; +/// let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?; /// assert_eq!("Hello World!".as_bytes(), plaintext); /// /// # Ok(()) @@ -241,7 +241,7 @@ pub enum OperatingMode { /// # 0x9d, /// # ]; /// # let key = UnboundCipherKey::new(&AES_128, key_bytes)?; -/// # let encrypting_key = EncryptingKey::ctr(key)?; +/// # let mut encrypting_key = EncryptingKey::ctr(key)?; /// # /// let context: CipherContext = encrypting_key.encrypt(&mut in_out_buffer)?; /// let iv_bytes: &[u8] = (&context).try_into()?; @@ -404,7 +404,6 @@ pub struct PaddedBlockEncryptingKey { key: UnboundCipherKey, mode: OperatingMode, padding: PaddingStrategy, - context: CipherContext, } impl PaddedBlockEncryptingKey { @@ -415,50 +414,16 @@ impl PaddedBlockEncryptingKey { /// * [`Unspecified`]: Returned if there is an error cosntructing a `PaddedBlockEncryptingKey`. /// pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result { - PaddedBlockEncryptingKey::new(key, OperatingMode::CBC, PaddingStrategy::PKCS7, None) - } - - /// Constructs a new `PaddedBlockEncryptingKey` cipher with chaining block cipher (CBC) mode. - /// The users provided context will be used for the CBC initialization-vector. - /// Plaintext data is padded following the PKCS#7 scheme. - /// - /// # Errors - /// * [`Unspecified`]: Returned if there is an error constructing a `PaddedBlockEncryptingKey`. - /// - pub fn less_safe_cbc_pkcs7( - key: UnboundCipherKey, - context: CipherContext, - ) -> Result { - PaddedBlockEncryptingKey::new( - key, - OperatingMode::CBC, - PaddingStrategy::PKCS7, - Some(context), - ) + PaddedBlockEncryptingKey::new(key, OperatingMode::CBC, PaddingStrategy::PKCS7) } + #[allow(clippy::unnecessary_wraps)] fn new( key: UnboundCipherKey, mode: OperatingMode, padding: PaddingStrategy, - context: Option, ) -> Result { - let mode_input = match context { - Some(mi) => { - if !key.algorithm().is_valid_cipher_context(mode, &mi) { - return Err(Unspecified); - } - mi - } - None => key.algorithm.new_cipher_context(mode)?, - }; - - Ok(PaddedBlockEncryptingKey { - key, - mode, - padding, - context: mode_input, - }) + Ok(PaddedBlockEncryptingKey { key, mode, padding }) } /// Returns the cipher algorithm. @@ -473,10 +438,18 @@ impl PaddedBlockEncryptingKey { self.mode } - /// Returns the cipher padding strategy. - #[must_use] - pub fn padding(&self) -> PaddingStrategy { - self.padding + /// Pads and encrypts data provided in `in_out` in-place. + /// Returns a references to the encryted data. + /// + /// # Errors + /// * [`Unspecified`]: Returned if encryption fails. + /// + pub fn encrypt(&self, in_out: &mut InOut) -> Result + where + InOut: AsMut<[u8]> + for<'a> Extend<&'a u8>, + { + let context = self.key.algorithm.new_cipher_context(self.mode)?; + self.less_safe_encrypt(in_out, context) } /// Pads and encrypts data provided in `in_out` in-place. @@ -485,17 +458,25 @@ impl PaddedBlockEncryptingKey { /// # Errors /// * [`Unspecified`]: Returned if encryption fails. /// - pub fn encrypt(self, in_out: &mut InOut) -> Result + pub fn less_safe_encrypt( + &self, + in_out: &mut InOut, + context: CipherContext, + ) -> Result where InOut: AsMut<[u8]> + for<'a> Extend<&'a u8>, { + if !self + .key + .algorithm() + .is_valid_cipher_context(self.mode, &context) + { + return Err(Unspecified); + } + self.padding .add_padding(self.algorithm().block_len(), in_out)?; - self.into_encrypting_key()?.encrypt(in_out.as_mut()) - } - - fn into_encrypting_key(self) -> Result { - EncryptingKey::new(self.key, self.mode, Some(self.context)) + encrypt(&self.key, self.mode, in_out.as_mut(), context) } } @@ -505,7 +486,6 @@ impl Debug for PaddedBlockEncryptingKey { .field("key", &self.key) .field("mode", &self.mode) .field("padding", &self.padding) - .field("context", &self.context) .finish() } } @@ -515,7 +495,6 @@ pub struct PaddedBlockDecryptingKey { key: UnboundCipherKey, mode: OperatingMode, padding: PaddingStrategy, - context: CipherContext, } impl PaddedBlockDecryptingKey { @@ -525,29 +504,17 @@ impl PaddedBlockDecryptingKey { /// # Errors /// * [`Unspecified`]: Returned if there is an error constructing the `PaddedBlockDecryptingKey`. /// - pub fn cbc_pkcs7( - key: UnboundCipherKey, - context: CipherContext, - ) -> Result { - PaddedBlockDecryptingKey::new(key, OperatingMode::CBC, PaddingStrategy::PKCS7, context) + pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result { + PaddedBlockDecryptingKey::new(key, OperatingMode::CBC, PaddingStrategy::PKCS7) } + #[allow(clippy::unnecessary_wraps)] fn new( key: UnboundCipherKey, mode: OperatingMode, padding: PaddingStrategy, - context: CipherContext, ) -> Result { - if !key.algorithm().is_valid_cipher_context(mode, &context) { - return Err(Unspecified); - } - - Ok(PaddedBlockDecryptingKey { - key, - mode, - padding, - context, - }) + Ok(PaddedBlockDecryptingKey { key, mode, padding }) } /// Returns the cipher algorithm. @@ -562,29 +529,31 @@ impl PaddedBlockDecryptingKey { self.mode } - /// Returns the cipher padding strategy. - #[must_use] - pub fn padding(&self) -> PaddingStrategy { - self.padding - } - /// Decrypts and unpads data provided in `in_out` in-place. /// Returns a references to the decrypted data. /// /// # Errors /// * [`Unspecified`]: Returned if decryption fails. /// - pub fn decrypt(self, in_out: &mut [u8]) -> Result<&mut [u8], Unspecified> { + pub fn decrypt<'in_out>( + &self, + in_out: &'in_out mut [u8], + context: CipherContext, + ) -> Result<&'in_out mut [u8], Unspecified> { + if !self + .key + .algorithm() + .is_valid_cipher_context(self.mode, &context) + { + return Err(Unspecified); + } + let block_len = self.algorithm().block_len(); let padding = self.padding; - let mut in_out = self.into_decrypting_key()?.decrypt(in_out)?; + let mut in_out = decrypt(&self.key, self.mode, in_out, context)?; in_out = padding.remove_padding(block_len, in_out)?; Ok(in_out) } - - fn into_decrypting_key(self) -> Result { - DecryptingKey::new(self.key, self.mode, self.context) - } } impl Debug for PaddedBlockDecryptingKey { @@ -593,7 +562,6 @@ impl Debug for PaddedBlockDecryptingKey { .field("key", &self.key) .field("mode", &self.mode) .field("padding", &self.padding) - .field("context", &self.context) .finish() } } @@ -602,7 +570,6 @@ impl Debug for PaddedBlockDecryptingKey { pub struct EncryptingKey { key: UnboundCipherKey, mode: OperatingMode, - context: CipherContext, } impl EncryptingKey { @@ -612,38 +579,12 @@ impl EncryptingKey { /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`. /// pub fn ctr(key: UnboundCipherKey) -> Result { - EncryptingKey::new(key, OperatingMode::CTR, None) + EncryptingKey::new(key, OperatingMode::CTR) } - /// Constructs an `EncryptingKey` operating in counter (CTR) mode using the provided key. - /// The users provided context will be used for the CTR mode initialization-vector. - /// - /// # Errors - /// * [`Unspecified`]: Returned if there is an error creating the `EncryptingKey`. - /// - pub fn less_safe_ctr( - key: UnboundCipherKey, - context: CipherContext, - ) -> Result { - EncryptingKey::new(key, OperatingMode::CTR, Some(context)) - } - - fn new( - key: UnboundCipherKey, - mode: OperatingMode, - context: Option, - ) -> Result { - let context = match context { - Some(mi) => { - if !key.algorithm().is_valid_cipher_context(mode, &mi) { - return Err(Unspecified); - } - mi - } - None => key.algorithm.new_cipher_context(mode)?, - }; - - Ok(EncryptingKey { key, mode, context }) + #[allow(clippy::unnecessary_wraps)] + fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result { + Ok(EncryptingKey { key, mode }) } /// Returns the cipher algorithm. @@ -665,30 +606,31 @@ impl EncryptingKey { /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length, /// and `in_out.len()` is not. Otherwise returned if encryption fails. /// - pub fn encrypt(self, in_out: &mut [u8]) -> Result { - let block_len = self.algorithm().block_len(); - - match self.mode { - OperatingMode::CTR => {} - _ => { - if (in_out.len() % block_len) != 0 { - return Err(Unspecified); - } - } - } + pub fn encrypt(&self, in_out: &mut [u8]) -> Result { + let context = self.key.algorithm.new_cipher_context(self.mode)?; + self.less_safe_encrypt(in_out, context) + } - match self.mode { - OperatingMode::CBC => match self.key.algorithm().id() { - AlgorithmId::Aes128 | AlgorithmId::Aes256 => { - encrypt_aes_cbc_mode(&self.key, self.context, in_out) - } - }, - OperatingMode::CTR => match self.key.algorithm().id() { - AlgorithmId::Aes128 | AlgorithmId::Aes256 => { - encrypt_aes_ctr_mode(&self.key, self.context, in_out) - } - }, + /// Encrypts the data provided in `in_out` in-place using the provided `CipherContext`. + /// Returns a references to the decrypted data. + /// + /// # Errors + /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length, + /// and `in_out.len()` is not. Otherwise returned if encryption fails. + /// + pub fn less_safe_encrypt( + &self, + in_out: &mut [u8], + context: CipherContext, + ) -> Result { + if !self + .key + .algorithm() + .is_valid_cipher_context(self.mode, &context) + { + return Err(Unspecified); } + encrypt(&self.key, self.mode, in_out, context) } } @@ -697,7 +639,6 @@ impl Debug for EncryptingKey { f.debug_struct("EncryptingKey") .field("key", &self.key) .field("mode", &self.mode) - .field("context", &self.context) .finish() } } @@ -706,7 +647,6 @@ impl Debug for EncryptingKey { pub struct DecryptingKey { key: UnboundCipherKey, mode: OperatingMode, - context: CipherContext, } impl DecryptingKey { @@ -715,23 +655,13 @@ impl DecryptingKey { /// # Errors /// * [`Unspecified`]: Returned if there is an error during decryption. /// - pub fn ctr( - key: UnboundCipherKey, - context: CipherContext, - ) -> Result { - DecryptingKey::new(key, OperatingMode::CTR, context) + pub fn ctr(key: UnboundCipherKey) -> Result { + DecryptingKey::new(key, OperatingMode::CTR) } - fn new( - key: UnboundCipherKey, - mode: OperatingMode, - context: CipherContext, - ) -> Result { - if !key.algorithm().is_valid_cipher_context(mode, &context) { - return Err(Unspecified); - } - - Ok(DecryptingKey { key, mode, context }) + #[allow(clippy::unnecessary_wraps)] + fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result { + Ok(DecryptingKey { key, mode }) } /// Returns the cipher algorithm. @@ -753,30 +683,12 @@ impl DecryptingKey { /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length, /// and `in_out.len()` is not. Also returned if decryption fails. /// - pub fn decrypt(self, in_out: &mut [u8]) -> Result<&mut [u8], Unspecified> { - let block_len = self.algorithm().block_len(); - - match self.mode { - OperatingMode::CTR => {} - _ => { - if (in_out.len() % block_len) != 0 { - return Err(Unspecified); - } - } - } - - match self.mode { - OperatingMode::CBC => match self.key.algorithm().id() { - AlgorithmId::Aes128 | AlgorithmId::Aes256 => { - decrypt_aes_cbc_mode(&self.key, self.context, in_out).map(|_| in_out) - } - }, - OperatingMode::CTR => match self.key.algorithm().id() { - AlgorithmId::Aes128 | AlgorithmId::Aes256 => { - decrypt_aes_ctr_mode(&self.key, self.context, in_out).map(|_| in_out) - } - }, - } + pub fn decrypt<'in_out>( + &self, + in_out: &'in_out mut [u8], + context: CipherContext, + ) -> Result<&'in_out mut [u8], Unspecified> { + decrypt(&self.key, self.mode, in_out, context) } } @@ -785,11 +697,68 @@ impl Debug for DecryptingKey { f.debug_struct("DecryptingKey") .field("key", &self.key) .field("mode", &self.mode) - .field("context", &self.context) .finish() } } +fn encrypt( + key: &UnboundCipherKey, + mode: OperatingMode, + in_out: &mut [u8], + context: CipherContext, +) -> Result { + let block_len = key.algorithm().block_len(); + + match mode { + OperatingMode::CTR => {} + _ => { + if (in_out.len() % block_len) != 0 { + return Err(Unspecified); + } + } + } + + match mode { + OperatingMode::CBC => match key.algorithm().id() { + AlgorithmId::Aes128 | AlgorithmId::Aes256 => encrypt_aes_cbc_mode(key, context, in_out), + }, + OperatingMode::CTR => match key.algorithm().id() { + AlgorithmId::Aes128 | AlgorithmId::Aes256 => encrypt_aes_ctr_mode(key, context, in_out), + }, + } +} + +fn decrypt<'in_out>( + key: &UnboundCipherKey, + mode: OperatingMode, + in_out: &'in_out mut [u8], + context: CipherContext, +) -> Result<&'in_out mut [u8], Unspecified> { + let block_len = key.algorithm().block_len(); + + match mode { + OperatingMode::CTR => {} + _ => { + if (in_out.len() % block_len) != 0 { + return Err(Unspecified); + } + } + } + + match mode { + OperatingMode::CBC => match key.algorithm().id() { + AlgorithmId::Aes128 | AlgorithmId::Aes256 => { + decrypt_aes_cbc_mode(key, context, in_out).map(|_| in_out) + } + }, + OperatingMode::CTR => match key.algorithm().id() { + AlgorithmId::Aes128 | AlgorithmId::Aes256 => { + decrypt_aes_ctr_mode(key, context, in_out).map(|_| in_out) + } + }, + } +} + fn encrypt_aes_ctr_mode( key: &UnboundCipherKey, context: CipherContext, @@ -947,30 +916,28 @@ mod tests { UnboundCipherKey::new(&AES_128, key_bytes).unwrap(), ) .unwrap(); - assert_eq!("PaddedBlockEncryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CBC, padding: PKCS7, context: Iv128 }", format!("{key:?}")); + assert_eq!("PaddedBlockEncryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CBC, padding: PKCS7 }", format!("{key:?}")); let mut data = vec![0u8; 16]; let context = key.encrypt(&mut data).unwrap(); assert_eq!("Iv128", format!("{context:?}")); let key = PaddedBlockDecryptingKey::cbc_pkcs7( UnboundCipherKey::new(&AES_128, key_bytes).unwrap(), - context, ) .unwrap(); - assert_eq!("PaddedBlockDecryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CBC, padding: PKCS7, context: Iv128 }", format!("{key:?}")); + assert_eq!("PaddedBlockDecryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CBC, padding: PKCS7 }", format!("{key:?}")); } { let key_bytes = &[0u8; 16]; let key = EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap(); - assert_eq!("EncryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CTR, context: Iv128 }", format!("{key:?}")); + assert_eq!("EncryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CTR }", format!("{key:?}")); let mut data = vec![0u8; 16]; let context = key.encrypt(&mut data).unwrap(); assert_eq!("Iv128", format!("{context:?}")); let key = - DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap(), context) - .unwrap(); - assert_eq!("DecryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CTR, context: Iv128 }", format!("{key:?}")); + DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap(); + assert_eq!("DecryptingKey { key: UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }, mode: CTR }", format!("{key:?}")); } } @@ -987,7 +954,7 @@ mod tests { } let cipher_key = UnboundCipherKey::new(alg, key).unwrap(); - let encrypting_key = EncryptingKey::new(cipher_key, mode, None).unwrap(); + let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap(); let mut in_out = input.clone(); let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap(); @@ -998,9 +965,9 @@ mod tests { } let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap(); - let decrypting_key = DecryptingKey::new(cipher_key2, mode, decrypt_iv).unwrap(); + let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap(); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap(); assert_eq!(input.as_slice(), plaintext); } @@ -1018,8 +985,7 @@ mod tests { } let cipher_key = UnboundCipherKey::new(alg, key).unwrap(); - let encrypting_key = - PaddedBlockEncryptingKey::new(cipher_key, mode, padding, None).unwrap(); + let encrypting_key = PaddedBlockEncryptingKey::new(cipher_key, mode, padding).unwrap(); let mut in_out = input.clone(); let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap(); @@ -1030,10 +996,9 @@ mod tests { } let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap(); - let decrypting_key = - PaddedBlockDecryptingKey::new(cipher_key2, mode, padding, decrypt_iv).unwrap(); + let decrypting_key = PaddedBlockDecryptingKey::new(cipher_key2, mode, padding).unwrap(); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap(); assert_eq!(input.as_slice(), plaintext); } @@ -1108,19 +1073,19 @@ mod tests { let unbound_key = UnboundCipherKey::new(alg, &key).unwrap(); let encrypting_key = - PaddedBlockEncryptingKey::new(unbound_key, $mode, $padding, Some(dc)).unwrap(); + PaddedBlockEncryptingKey::new(unbound_key, $mode, $padding).unwrap(); let mut in_out = input.clone(); - let context = encrypting_key.encrypt(&mut in_out).unwrap(); + let context = encrypting_key.less_safe_encrypt(&mut in_out, dc).unwrap(); assert_eq!(expected_ciphertext, in_out); let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap(); let decrypting_key = - PaddedBlockDecryptingKey::new(unbound_key2, $mode, $padding, context).unwrap(); + PaddedBlockDecryptingKey::new(unbound_key2, $mode, $padding).unwrap(); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); assert_eq!(input.as_slice(), plaintext); } }; @@ -1150,18 +1115,18 @@ mod tests { let unbound_key = UnboundCipherKey::new(alg, &key).unwrap(); - let encrypting_key = EncryptingKey::new(unbound_key, $mode, Some(dc)).unwrap(); + let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap(); let mut in_out = input.clone(); - let context = encrypting_key.encrypt(&mut in_out).unwrap(); + let context = encrypting_key.less_safe_encrypt(&mut in_out, dc).unwrap(); assert_eq!(expected_ciphertext, in_out); let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap(); - let decrypting_key = DecryptingKey::new(unbound_key2, $mode, context).unwrap(); + let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap(); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); assert_eq!(input.as_slice(), plaintext); } }; diff --git a/aws-lc-rs/tests/cipher_test.rs b/aws-lc-rs/tests/cipher_test.rs index 0d47b1c9b50..68534d70bad 100644 --- a/aws-lc-rs/tests/cipher_test.rs +++ b/aws-lc-rs/tests/cipher_test.rs @@ -3,44 +3,44 @@ use aws_lc_rs::cipher::{ CipherContext, DecryptingKey, EncryptingKey, OperatingMode, PaddedBlockDecryptingKey, - PaddedBlockEncryptingKey, PaddingStrategy, UnboundCipherKey, AES_128, AES_256, + PaddedBlockEncryptingKey, UnboundCipherKey, AES_128, AES_256, }; use aws_lc_rs::iv::FixedLength; use aws_lc_rs::test::from_hex; macro_rules! padded_cipher_kat { - ($name:ident, $alg:expr, $mode:expr, $padding:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => { paste::item! { - #[test] - fn $name() { - let key = from_hex($key).unwrap(); - let input = from_hex($plaintext).unwrap(); - let expected_ciphertext = from_hex($ciphertext).unwrap(); + ($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => { + paste::item! { + #[test] + fn $name() { + let key = from_hex($key).unwrap(); + let input = from_hex($plaintext).unwrap(); + let expected_ciphertext = from_hex($ciphertext).unwrap(); - let iv = from_hex($iv).unwrap(); - let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap(); - let context = CipherContext::Iv128(fixed_iv); + let iv = from_hex($iv).unwrap(); + let fixed_iv = FixedLength::try_from(iv.as_slice()).unwrap(); + let context = CipherContext::Iv128(fixed_iv); - let unbound_key = UnboundCipherKey::new($alg, &key).unwrap(); + let unbound_key = UnboundCipherKey::new($alg, &key).unwrap(); - let encrypting_key = - PaddedBlockEncryptingKey::[](unbound_key, context).unwrap(); - assert_eq!($mode, encrypting_key.mode()); - assert_eq!($padding, encrypting_key.padding()); - assert_eq!($alg, encrypting_key.algorithm()); - let mut in_out = input.clone(); - let context = encrypting_key.encrypt(&mut in_out).unwrap(); - assert_eq!(expected_ciphertext.as_slice(), in_out.as_slice()); + let encrypting_key = + PaddedBlockEncryptingKey::$constructor(unbound_key).unwrap(); + assert_eq!($mode, encrypting_key.mode()); + assert_eq!($alg, encrypting_key.algorithm()); + let mut in_out = input.clone(); + let context = encrypting_key.less_safe_encrypt(&mut in_out, context).unwrap(); + assert_eq!(expected_ciphertext.as_slice(), in_out.as_slice()); - let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap(); - let decrypting_key = - PaddedBlockDecryptingKey::$constructor(unbound_key2, context).unwrap(); - assert_eq!($mode, decrypting_key.mode()); - assert_eq!($padding, decrypting_key.padding()); - assert_eq!($alg, decrypting_key.algorithm()); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); - assert_eq!(input.as_slice(), plaintext); + let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap(); + let decrypting_key = + PaddedBlockDecryptingKey::$constructor(unbound_key2).unwrap(); + assert_eq!($mode, decrypting_key.mode()); + assert_eq!($alg, decrypting_key.algorithm()); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); + assert_eq!(input.as_slice(), plaintext); + } } - }}; + }; } macro_rules! cipher_kat { @@ -59,19 +59,19 @@ macro_rules! cipher_kat { let unbound_key = UnboundCipherKey::new($alg, &key).unwrap(); let encrypting_key = - EncryptingKey::[](unbound_key, context).unwrap(); + EncryptingKey::$constructor(unbound_key).unwrap(); assert_eq!($mode, encrypting_key.mode()); assert_eq!($alg, encrypting_key.algorithm()); let mut in_out = input.clone(); - let context = encrypting_key.encrypt(in_out.as_mut_slice()).unwrap(); + let context = encrypting_key.less_safe_encrypt(in_out.as_mut_slice(), context).unwrap(); assert_eq!(expected_ciphertext.as_slice(), in_out); let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap(); let decrypting_key = - DecryptingKey::$constructor(unbound_key2, context).unwrap(); + DecryptingKey::$constructor(unbound_key2).unwrap(); assert_eq!($mode, decrypting_key.mode()); assert_eq!($alg, decrypting_key.algorithm()); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); assert_eq!(input.as_slice(), plaintext); } } @@ -79,7 +79,7 @@ macro_rules! cipher_kat { } macro_rules! padded_cipher_rt { - ($name:ident, $alg:expr, $mode:expr, $padding:expr, $constructor:ident, $key:literal, $plaintext:literal) => { + ($name:ident, $alg:expr, $mode:expr, $constructor:ident, $key:literal, $plaintext:literal) => { paste::item! { #[test] fn $name() { @@ -89,18 +89,16 @@ macro_rules! padded_cipher_rt { let encrypting_key = PaddedBlockEncryptingKey::$constructor(unbound_key).unwrap(); assert_eq!($mode, encrypting_key.mode()); - assert_eq!($padding, encrypting_key.padding()); assert_eq!($alg, encrypting_key.algorithm()); let mut in_out = input.clone(); let context = encrypting_key.encrypt(&mut in_out).unwrap(); let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap(); let decrypting_key = - PaddedBlockDecryptingKey::$constructor(unbound_key2, context).unwrap(); + PaddedBlockDecryptingKey::$constructor(unbound_key2).unwrap(); assert_eq!($mode, decrypting_key.mode()); - assert_eq!($padding, decrypting_key.padding()); assert_eq!($alg, decrypting_key.algorithm()); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); assert_eq!(input.as_slice(), plaintext); } } @@ -122,10 +120,10 @@ macro_rules! cipher_rt { let context = encrypting_key.encrypt(in_out.as_mut_slice()).unwrap(); let unbound_key2 = UnboundCipherKey::new($alg, &key).unwrap(); - let decrypting_key = DecryptingKey::$constructor(unbound_key2, context).unwrap(); + let decrypting_key = DecryptingKey::$constructor(unbound_key2).unwrap(); assert_eq!($mode, decrypting_key.mode()); assert_eq!($alg, decrypting_key.algorithm()); - let plaintext = decrypting_key.decrypt(&mut in_out).unwrap(); + let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap(); assert_eq!(input.as_slice(), plaintext); } }; @@ -135,7 +133,6 @@ padded_cipher_kat!( test_kat_aes_128_cbc_16_bytes, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "000102030405060708090a0b0c0d0e0f", "00000000000000000000000000000000", @@ -147,7 +144,6 @@ padded_cipher_kat!( test_kat_aes_256_cbc_15_bytes, &AES_256, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00000000000000000000000000000000", @@ -203,7 +199,6 @@ padded_cipher_kat!( test_kat_aes_128_cbc_15_bytes, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "053304bb3899e1d99db9d29343ea782d", "b5313560244a4822c46c2a0c9d0cf7fd", @@ -215,7 +210,6 @@ padded_cipher_kat!( test_kat_aes_128_cbc_16_bytes_2, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "95af71f1c63e4a1d0b0b1a27fb978283", "89e40797dca70197ff87d3dbb0ef2802", @@ -227,7 +221,6 @@ padded_cipher_kat!( test_kat_aes_256_cbc_16_bytes, &AES_256, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41", "24f6076548fb9d93c8f7ed9f6e661ef9", @@ -239,7 +232,6 @@ padded_cipher_rt!( test_rt_aes_128_cbc_16_bytes, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff" @@ -249,7 +241,6 @@ padded_cipher_rt!( test_rt_aes_256_cbc_15_bytes, &AES_256, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddee" @@ -313,7 +304,6 @@ padded_cipher_rt!( test_rt_aes_128_cbc_15_bytes, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "053304bb3899e1d99db9d29343ea782d", "a3e4c990356c01f320043c3d8d6f43" @@ -323,7 +313,6 @@ padded_cipher_rt!( test_rt_aes_128_cbc_16_bytes_2, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "95af71f1c63e4a1d0b0b1a27fb978283", "aece7b5e3c3df1ffc9802d2dfe296dc7" @@ -333,7 +322,6 @@ padded_cipher_rt!( test_rt_128_cbc_17_bytes, &AES_128, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "95af71f1c63e4a1d0b0b1a27fb978283", "aece7b5e3c3df1ffc9802d2dfe296dc734" @@ -343,7 +331,6 @@ padded_cipher_rt!( test_rt_aes_256_cbc_16_bytes, &AES_256, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41", "a39c1fdf77ea3e1f18178c0ec237c70a" @@ -353,7 +340,6 @@ padded_cipher_rt!( test_rt_aes_256_cbc_17_bytes, &AES_256, OperatingMode::CBC, - PaddingStrategy::PKCS7, cbc_pkcs7, "d4a8206dcae01242f9db79a4ecfe277d0f7bb8ccbafd8f9809adb39f35aa9b41", "a39c1fdf77ea3e1f18178c0ec237c70a34"