aws_lc_rs/
cipher.rs

1// Copyright 2018 Brian Smith.
2// SPDX-License-Identifier: ISC
3// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6//! Block and Stream Ciphers for Encryption and Decryption.
7//!
8//! # 🛑 Read Before Using
9//!
10//! This module provides access to block and stream cipher algorithms.
11//! The modes provided here only provide confidentiality, but **do not**
12//! provide integrity or authentication verification of ciphertext.
13//!
14//! These algorithms are provided solely for applications requiring them
15//! in order to maintain backwards compatibility in legacy applications.
16//!
17//! If you are developing new applications requiring data encryption see
18//! the algorithms provided in [`aead`](crate::aead).
19//!
20//! # Examples
21//!
22//! ## Encryption Modes
23//!
24//! ### AES-128 CBC
25//!
26//! ```rust
27//! # use std::error::Error;
28//! #
29//! # fn main() -> Result<(), Box<dyn Error>> {
30//! use aws_lc_rs::cipher::{
31//!     PaddedBlockDecryptingKey, PaddedBlockEncryptingKey, UnboundCipherKey, AES_128,
32//! };
33//! use std::io::Read;
34//!
35//! let original_message = "This is a secret message!".as_bytes();
36//! let mut in_out_buffer = Vec::from(original_message);
37//!
38//! let key_bytes: &[u8] = &[
39//!     0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c, 0xb6,
40//!     0xd1,
41//! ];
42//!
43//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
44//! let mut encrypting_key = PaddedBlockEncryptingKey::cbc_pkcs7(key)?;
45//! let context = encrypting_key.encrypt(&mut in_out_buffer)?;
46//!
47//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
48//! let mut decrypting_key = PaddedBlockDecryptingKey::cbc_pkcs7(key)?;
49//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?;
50//! assert_eq!(original_message, plaintext);
51//! #
52//! #
53//! # Ok(())
54//! # }
55//! ```
56//!
57//! ### AES-128 CTR
58//!
59//! ```rust
60//! # use std::error::Error;
61//! #
62//! # fn main() -> Result<(), Box<dyn Error>> {
63//! use aws_lc_rs::cipher::{DecryptingKey, EncryptingKey, UnboundCipherKey, AES_128};
64//!
65//! let original_message = "This is a secret message!".as_bytes();
66//! let mut in_out_buffer = Vec::from(original_message);
67//!
68//! let key_bytes: &[u8] = &[
69//!     0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c, 0xb6,
70//!     0xd1,
71//! ];
72//!
73//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
74//! let mut encrypting_key = EncryptingKey::ctr(key)?;
75//! let context = encrypting_key.encrypt(&mut in_out_buffer)?;
76//!
77//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
78//! let mut decrypting_key = DecryptingKey::ctr(key)?;
79//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?;
80//! assert_eq!(original_message, plaintext);
81//! #
82//! # Ok(())
83//! # }
84//! ```
85//!
86//! ### AES-128 CBC Streaming Cipher
87//!
88//! ```rust
89//! # use std::error::Error;
90//! #
91//! # fn main() -> Result<(), Box<dyn Error>> {
92//! use aws_lc_rs::cipher::{
93//!     StreamingDecryptingKey, StreamingEncryptingKey, UnboundCipherKey, AES_128,
94//! };
95//! let original_message = "This is a secret message!".as_bytes();
96//! let key_bytes: &[u8] = &[
97//!     0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c,
98//!     0xb6, 0xd1,
99//! ];
100//! // Prepare ciphertext buffer
101//! let mut ciphertext_buffer = vec![0u8; original_message.len() + AES_128.block_len()];
102//! let ciphertext_slice = ciphertext_buffer.as_mut_slice();
103//!
104//! // Create StreamingEncryptingKey
105//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
106//! let mut encrypting_key = StreamingEncryptingKey::cbc_pkcs7(key).unwrap();
107//!
108//! // Encrypt
109//! let mut first_update = encrypting_key
110//!                            .update(original_message, ciphertext_slice)
111//!                            .unwrap();
112//! let first_update_len = first_update.written().len();
113//! let (context, final_update) = encrypting_key.finish(first_update.remainder_mut()).unwrap();
114//! let ciphertext_len = first_update_len + final_update.written().len();
115//! let ciphertext = &ciphertext_slice[0..ciphertext_len];
116//!
117//! // Prepare plaintext buffer
118//! let mut plaintext_buffer = vec![0u8; ciphertext_len + AES_128.block_len()];
119//! let plaintext_slice = plaintext_buffer.as_mut_slice();
120//!
121//! // Create StreamingDecryptingKey
122//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
123//! let mut decrypting_key = StreamingDecryptingKey::cbc_pkcs7(key, context).unwrap();
124//!
125//! // Decrypt
126//! let mut first_update = decrypting_key.update(ciphertext, plaintext_slice).unwrap();
127//! let first_update_len = first_update.written().len();
128//! let final_update = decrypting_key.finish(first_update.remainder_mut()).unwrap();
129//! let plaintext_len = first_update_len + final_update.written().len();
130//! let plaintext = &plaintext_slice[0..plaintext_len];
131//!
132//! assert_eq!(original_message, plaintext);
133//! #
134//! # Ok(())
135//! # }
136//! ```
137//!
138//! ### AES-128 CFB 128-bit mode
139//!
140//! ```rust
141//! # use std::error::Error;
142//! #
143//! # fn main() -> Result<(), Box<dyn Error>> {
144//! use aws_lc_rs::cipher::{DecryptingKey, EncryptingKey, UnboundCipherKey, AES_128};
145//!
146//! let original_message = "This is a secret message!".as_bytes();
147//! let mut in_out_buffer = Vec::from(original_message);
148//!
149//! let key_bytes: &[u8] = &[
150//!     0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c, 0xb6,
151//!     0xd1,
152//! ];
153//!
154//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
155//! let mut encrypting_key = EncryptingKey::cfb128(key)?;
156//! let context = encrypting_key.encrypt(&mut in_out_buffer)?;
157//!
158//! let key = UnboundCipherKey::new(&AES_128, key_bytes)?;
159//! let mut decrypting_key = DecryptingKey::cfb128(key)?;
160//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?;
161//! assert_eq!(original_message, plaintext);
162//! #
163//! # Ok(())
164//! # }
165//! ```
166//!
167//! ## Constructing a `DecryptionContext` for decryption.
168//!
169//! ```rust
170//! # use std::error::Error;
171//! # fn main() -> Result<(), Box<dyn Error>> {
172//! use aws_lc_rs::cipher::{DecryptingKey, DecryptionContext, UnboundCipherKey, AES_128};
173//! use aws_lc_rs::iv::{FixedLength, IV_LEN_128_BIT};
174//!
175//! let context = DecryptionContext::Iv128(FixedLength::<IV_LEN_128_BIT>::from(&[
176//!     0x8d, 0xdb, 0x7d, 0xf1, 0x56, 0xf5, 0x1c, 0xde, 0x63, 0xe3, 0x4a, 0x34, 0xb0, 0xdf, 0x28,
177//!     0xf0,
178//! ]));
179//!
180//! let ciphertext: &[u8] = &[
181//!     0x79, 0x8c, 0x04, 0x58, 0xcf, 0x98, 0xb1, 0xe9, 0x97, 0x6b, 0xa1, 0xce,
182//! ];
183//!
184//! let mut in_out_buffer = Vec::from(ciphertext);
185//!
186//! let key = UnboundCipherKey::new(
187//!     &AES_128,
188//!     &[
189//!         0x5b, 0xfc, 0xe7, 0x5e, 0x57, 0xc5, 0x4d, 0xda, 0x2d, 0xd4, 0x7e, 0x07, 0x0a, 0xef,
190//!         0x43, 0x29,
191//!     ],
192//! )?;
193//! let mut decrypting_key = DecryptingKey::ctr(key)?;
194//! let plaintext = decrypting_key.decrypt(&mut in_out_buffer, context)?;
195//! assert_eq!("Hello World!".as_bytes(), plaintext);
196//!
197//! # Ok(())
198//! # }
199//! ```
200//!
201//! ## Getting an immutable reference to the IV slice.
202//!
203//! `TryFrom<&DecryptionContext>` is implemented for `&[u8]` allowing immutable references
204//! to IV bytes returned from cipher encryption operations. Note this is implemented as a `TryFrom` as it
205//! may fail for future enum variants that aren't representable as a single slice.
206//!
207//! ```rust
208//! # use std::error::Error;
209//! # fn main() -> Result<(), Box<dyn Error>> {
210//! # use aws_lc_rs::cipher::DecryptionContext;
211//! # use aws_lc_rs::iv::FixedLength;
212//! # let x: DecryptionContext = DecryptionContext::Iv128(FixedLength::from([0u8; 16]));
213//! // x is type `DecryptionContext`
214//! let iv: &[u8] = (&x).try_into()?;
215//! # Ok(())
216//! # }
217//! ```
218
219#![allow(clippy::module_name_repetitions)]
220
221pub(crate) mod aes;
222pub(crate) mod block;
223pub(crate) mod chacha;
224pub(crate) mod key;
225mod padded;
226mod streaming;
227
228pub use padded::{PaddedBlockDecryptingKey, PaddedBlockEncryptingKey};
229pub use streaming::{BufferUpdate, StreamingDecryptingKey, StreamingEncryptingKey};
230
231use crate::aws_lc::{
232    EVP_aes_128_cbc, EVP_aes_128_cfb128, EVP_aes_128_ctr, EVP_aes_128_ecb, EVP_aes_192_cbc,
233    EVP_aes_192_cfb128, EVP_aes_192_ctr, EVP_aes_192_ecb, EVP_aes_256_cbc, EVP_aes_256_cfb128,
234    EVP_aes_256_ctr, EVP_aes_256_ecb, EVP_CIPHER,
235};
236use crate::buffer::Buffer;
237use crate::error::Unspecified;
238use crate::hkdf;
239use crate::hkdf::KeyType;
240use crate::iv::{FixedLength, IV_LEN_128_BIT};
241use crate::ptr::ConstPointer;
242use core::fmt::Debug;
243use key::SymmetricCipherKey;
244
245/// The number of bytes in an AES 128-bit key
246pub use crate::cipher::aes::AES_128_KEY_LEN;
247
248/// The number of bytes in an AES 192-bit key
249pub use crate::cipher::aes::AES_192_KEY_LEN;
250
251/// The number of bytes in an AES 256-bit key
252pub use crate::cipher::aes::AES_256_KEY_LEN;
253
254const MAX_CIPHER_KEY_LEN: usize = AES_256_KEY_LEN;
255
256/// The number of bytes for an AES-CBC initialization vector (IV)
257pub use crate::cipher::aes::AES_CBC_IV_LEN;
258
259/// The number of bytes for an AES-CTR initialization vector (IV)
260pub use crate::cipher::aes::AES_CTR_IV_LEN;
261
262/// The number of bytes for an AES-CFB initialization vector (IV)
263pub use crate::cipher::aes::AES_CFB_IV_LEN;
264
265use crate::cipher::aes::AES_BLOCK_LEN;
266
267const MAX_CIPHER_BLOCK_LEN: usize = AES_BLOCK_LEN;
268
269/// The cipher operating mode.
270#[non_exhaustive]
271#[derive(Debug, PartialEq, Eq, Clone, Copy)]
272pub enum OperatingMode {
273    /// Cipher block chaining (CBC) mode.
274    CBC,
275
276    /// Counter (CTR) mode.
277    CTR,
278
279    /// CFB 128-bit mode.
280    CFB128,
281
282    /// Electronic Code Book (ECB) mode.
283    ECB,
284}
285
286impl OperatingMode {
287    fn evp_cipher(&self, algorithm: &Algorithm) -> ConstPointer<'_, EVP_CIPHER> {
288        unsafe {
289            ConstPointer::new_static(match (self, algorithm.id) {
290                (OperatingMode::CBC, AlgorithmId::Aes128) => EVP_aes_128_cbc(),
291                (OperatingMode::CTR, AlgorithmId::Aes128) => EVP_aes_128_ctr(),
292                (OperatingMode::CFB128, AlgorithmId::Aes128) => EVP_aes_128_cfb128(),
293                (OperatingMode::ECB, AlgorithmId::Aes128) => EVP_aes_128_ecb(),
294                (OperatingMode::CBC, AlgorithmId::Aes192) => EVP_aes_192_cbc(),
295                (OperatingMode::CTR, AlgorithmId::Aes192) => EVP_aes_192_ctr(),
296                (OperatingMode::CFB128, AlgorithmId::Aes192) => EVP_aes_192_cfb128(),
297                (OperatingMode::ECB, AlgorithmId::Aes192) => EVP_aes_192_ecb(),
298                (OperatingMode::CBC, AlgorithmId::Aes256) => EVP_aes_256_cbc(),
299                (OperatingMode::CTR, AlgorithmId::Aes256) => EVP_aes_256_ctr(),
300                (OperatingMode::CFB128, AlgorithmId::Aes256) => EVP_aes_256_cfb128(),
301                (OperatingMode::ECB, AlgorithmId::Aes256) => EVP_aes_256_ecb(),
302            })
303            .unwrap()
304        }
305    }
306}
307
308macro_rules! define_cipher_context {
309    ($name:ident, $other:ident) => {
310        /// The contextual data used to encrypt or decrypt data.
311        #[non_exhaustive]
312        pub enum $name {
313            /// A 128-bit Initialization Vector.
314            Iv128(FixedLength<IV_LEN_128_BIT>),
315
316            /// No Cipher Context
317            None,
318        }
319
320        impl<'a> TryFrom<&'a $name> for &'a [u8] {
321            type Error = Unspecified;
322
323            fn try_from(value: &'a $name) -> Result<Self, Unspecified> {
324                match value {
325                    $name::Iv128(iv) => Ok(iv.as_ref()),
326                    _ => Err(Unspecified),
327                }
328            }
329        }
330
331        impl Debug for $name {
332            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
333                match self {
334                    Self::Iv128(_) => write!(f, "Iv128"),
335                    Self::None => write!(f, "None"),
336                }
337            }
338        }
339
340        impl From<$other> for $name {
341            fn from(value: $other) -> Self {
342                match value {
343                    $other::Iv128(iv) => $name::Iv128(iv),
344                    $other::None => $name::None,
345                }
346            }
347        }
348    };
349}
350
351define_cipher_context!(EncryptionContext, DecryptionContext);
352define_cipher_context!(DecryptionContext, EncryptionContext);
353
354#[non_exhaustive]
355#[derive(Debug, PartialEq, Eq, Clone, Copy)]
356/// Cipher algorithm identifier.
357pub enum AlgorithmId {
358    /// AES 128-bit
359    Aes128,
360
361    /// AES 256-bit
362    Aes256,
363
364    /// AES 192-bit
365    Aes192,
366}
367
368/// A cipher algorithm.
369#[derive(Debug, PartialEq, Eq)]
370pub struct Algorithm {
371    id: AlgorithmId,
372    key_len: usize,
373    block_len: usize,
374}
375
376/// AES 128-bit cipher
377pub const AES_128: Algorithm = Algorithm {
378    id: AlgorithmId::Aes128,
379    key_len: AES_128_KEY_LEN,
380    block_len: AES_BLOCK_LEN,
381};
382
383/// AES 192-bit cipher
384pub const AES_192: Algorithm = Algorithm {
385    id: AlgorithmId::Aes192,
386    key_len: AES_192_KEY_LEN,
387    block_len: AES_BLOCK_LEN,
388};
389
390/// AES 256-bit cipher
391pub const AES_256: Algorithm = Algorithm {
392    id: AlgorithmId::Aes256,
393    key_len: AES_256_KEY_LEN,
394    block_len: AES_BLOCK_LEN,
395};
396
397impl Algorithm {
398    fn id(&self) -> &AlgorithmId {
399        &self.id
400    }
401
402    /// The block length of this cipher algorithm.
403    #[must_use]
404    pub const fn block_len(&self) -> usize {
405        self.block_len
406    }
407
408    fn new_encryption_context(
409        &self,
410        mode: OperatingMode,
411    ) -> Result<EncryptionContext, Unspecified> {
412        match self.id {
413            // TODO: Hopefully support CFB1, and CFB8
414            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
415                OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
416                    Ok(EncryptionContext::Iv128(FixedLength::new()?))
417                }
418                OperatingMode::ECB => Ok(EncryptionContext::None),
419            },
420        }
421    }
422
423    fn is_valid_encryption_context(&self, mode: OperatingMode, input: &EncryptionContext) -> bool {
424        match self.id {
425            // TODO: Hopefully support CFB1, and CFB8
426            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
427                OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
428                    matches!(input, EncryptionContext::Iv128(_))
429                }
430                OperatingMode::ECB => {
431                    matches!(input, EncryptionContext::None)
432                }
433            },
434        }
435    }
436
437    fn is_valid_decryption_context(&self, mode: OperatingMode, input: &DecryptionContext) -> bool {
438        // TODO: Hopefully support CFB1, and CFB8
439        match self.id {
440            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => match mode {
441                OperatingMode::CBC | OperatingMode::CTR | OperatingMode::CFB128 => {
442                    matches!(input, DecryptionContext::Iv128(_))
443                }
444                OperatingMode::ECB => {
445                    matches!(input, DecryptionContext::None)
446                }
447            },
448        }
449    }
450}
451
452#[allow(clippy::missing_fields_in_debug)]
453impl Debug for UnboundCipherKey {
454    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
455        f.debug_struct("UnboundCipherKey")
456            .field("algorithm", &self.algorithm)
457            .finish()
458    }
459}
460
461impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundCipherKey {
462    fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
463        let mut key_bytes = [0; MAX_CIPHER_KEY_LEN];
464        let key_bytes = &mut key_bytes[..okm.len().key_len];
465        let algorithm = *okm.len();
466        okm.fill(key_bytes).unwrap();
467        Self::new(algorithm, key_bytes).unwrap()
468    }
469}
470
471impl KeyType for &'static Algorithm {
472    fn len(&self) -> usize {
473        self.key_len
474    }
475}
476
477/// A key bound to a particular cipher algorithm.
478pub struct UnboundCipherKey {
479    algorithm: &'static Algorithm,
480    key_bytes: Buffer<'static, &'static [u8]>,
481}
482
483impl UnboundCipherKey {
484    /// Constructs an [`UnboundCipherKey`].
485    ///
486    /// # Errors
487    ///
488    /// * [`Unspecified`] if `key_bytes.len()` does not match the length required by `algorithm`.
489    pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self, Unspecified> {
490        let key_bytes = Buffer::new(key_bytes.to_vec());
491        Ok(UnboundCipherKey {
492            algorithm,
493            key_bytes,
494        })
495    }
496
497    #[inline]
498    #[must_use]
499    /// Returns the algorithm associated with this key.
500    pub fn algorithm(&self) -> &'static Algorithm {
501        self.algorithm
502    }
503}
504
505impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
506    type Error = Unspecified;
507
508    fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
509        match self.algorithm.id() {
510            AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
511            AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
512            AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
513        }
514    }
515}
516
517/// A cipher encryption key that does not perform block padding.
518pub struct EncryptingKey {
519    algorithm: &'static Algorithm,
520    key: SymmetricCipherKey,
521    mode: OperatingMode,
522}
523
524impl EncryptingKey {
525    /// Constructs an `EncryptingKey` operating in counter (CTR) mode using the provided key.
526    ///
527    // # FIPS
528    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
529    // * `AES_128`
530    // * `AES_256`
531    //
532    /// # Errors
533    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
534    pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
535        Self::new(key, OperatingMode::CTR)
536    }
537
538    /// Constructs an `EncryptingKey` operating in cipher feedback 128-bit mode (CFB128) using the provided key.
539    ///
540    // # FIPS
541    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
542    // * `AES_128`
543    // * `AES_256`
544    //
545    /// # Errors
546    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
547    pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
548        Self::new(key, OperatingMode::CFB128)
549    }
550
551    /// Constructs an `EncryptingKey` operating in cipher block chaining (CBC) mode using the provided key.
552    ///
553    /// # ☠️ ️️️DANGER ☠️
554    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
555    /// very likely not what you want to use.
556    ///
557    // # FIPS
558    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
559    // * `AES_128`
560    // * `AES_256`
561    //
562    /// # Errors
563    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
564    pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
565        Self::new(key, OperatingMode::CBC)
566    }
567
568    /// Constructs an `EncryptingKey` operating in electronic code book mode (ECB) using the provided key.
569    ///
570    /// # ☠️ ️️️DANGER ☠️
571    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
572    /// very likely not what you want to use.
573    ///
574    // # FIPS
575    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
576    // * `AES_128`
577    // * `AES_256`
578    //
579    /// # Errors
580    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
581    pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
582        Self::new(key, OperatingMode::ECB)
583    }
584
585    #[allow(clippy::unnecessary_wraps)]
586    fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
587        let algorithm = key.algorithm();
588        let key = key.try_into()?;
589        Ok(Self {
590            algorithm,
591            key,
592            mode,
593        })
594    }
595
596    /// Returns the cipher algorithm.
597    #[must_use]
598    pub fn algorithm(&self) -> &Algorithm {
599        self.algorithm
600    }
601
602    /// Returns the cipher operating mode.
603    #[must_use]
604    pub fn mode(&self) -> OperatingMode {
605        self.mode
606    }
607
608    /// Encrypts the data provided in `in_out` in-place.
609    /// Returns a [`DecryptionContext`] with the randomly generated IV that was used to encrypt
610    /// the data provided.
611    ///
612    /// If `EncryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
613    /// of the block length.
614    ///
615    /// # Errors
616    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
617    ///   and `in_out.len()` is not. Otherwise, returned if encryption fails.
618    pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
619        let context = self.algorithm.new_encryption_context(self.mode)?;
620        self.less_safe_encrypt(in_out, context)
621    }
622
623    /// Encrypts the data provided in `in_out` in-place using the provided `EncryptionContext`.
624    /// This is considered "less safe" because the caller could potentially construct
625    /// a `EncryptionContext` from a previously used IV (initialization vector).
626    /// Returns a [`DecryptionContext`] produced from the provided `EncryptionContext`.
627    ///
628    /// If `EncryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
629    /// of the block length.
630    ///
631    /// # Errors
632    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
633    ///   and `in_out.len()` is not. Otherwise returned if encryption fails.
634    pub fn less_safe_encrypt(
635        &self,
636        in_out: &mut [u8],
637        context: EncryptionContext,
638    ) -> Result<DecryptionContext, Unspecified> {
639        if !self
640            .algorithm()
641            .is_valid_encryption_context(self.mode, &context)
642        {
643            return Err(Unspecified);
644        }
645        encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
646    }
647}
648
649impl Debug for EncryptingKey {
650    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
651        f.debug_struct("EncryptingKey")
652            .field("algorithm", self.algorithm)
653            .field("mode", &self.mode)
654            .finish_non_exhaustive()
655    }
656}
657
658/// A cipher decryption key that does not perform block padding.
659pub struct DecryptingKey {
660    algorithm: &'static Algorithm,
661    key: SymmetricCipherKey,
662    mode: OperatingMode,
663}
664
665impl DecryptingKey {
666    /// Constructs a cipher decrypting key operating in counter (CTR) mode using the provided key and context.
667    ///
668    // # FIPS
669    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
670    // * `AES_128`
671    // * `AES_256`
672    //
673    /// # Errors
674    /// * [`Unspecified`]: Returned if there is an error during decryption.
675    pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
676        Self::new(key, OperatingMode::CTR)
677    }
678
679    /// Constructs a cipher decrypting key operating in cipher feedback 128-bit mode (CFB128) using the provided key and context.
680    ///
681    // # FIPS
682    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
683    // * `AES_128`
684    // * `AES_256`
685    //
686    /// # Errors
687    /// * [`Unspecified`]: Returned if there is an error during decryption.
688    pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
689        Self::new(key, OperatingMode::CFB128)
690    }
691
692    /// Constructs an `DecryptingKey` operating in cipher block chaining (CBC) mode using the provided key and context.
693    ///
694    /// # ☠️ ️️️DANGER ☠️
695    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
696    /// very likely not what you want to use.
697    ///
698    // # FIPS
699    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
700    // * `AES_128`
701    // * `AES_256`
702    //
703    /// # Errors
704    /// * [`Unspecified`]: Returned if there is an error during decryption.
705    pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
706        Self::new(key, OperatingMode::CBC)
707    }
708
709    /// Constructs an `DecryptingKey` operating in electronic code book (ECB) mode using the provided key.
710    ///
711    /// # ☠️ ️️️DANGER ☠️
712    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
713    /// very likely not what you want to use.
714    ///
715    // # FIPS
716    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
717    // * `AES_128`
718    // * `AES_256`
719    //
720    /// # Errors
721    /// * [`Unspecified`]: Returned if there is an error constructing the `DecryptingKey`.
722    pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
723        Self::new(key, OperatingMode::ECB)
724    }
725
726    #[allow(clippy::unnecessary_wraps)]
727    fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
728        let algorithm = key.algorithm();
729        let key = key.try_into()?;
730        Ok(Self {
731            algorithm,
732            key,
733            mode,
734        })
735    }
736
737    /// Returns the cipher algorithm.
738    #[must_use]
739    pub fn algorithm(&self) -> &Algorithm {
740        self.algorithm
741    }
742
743    /// Returns the cipher operating mode.
744    #[must_use]
745    pub fn mode(&self) -> OperatingMode {
746        self.mode
747    }
748
749    /// Decrypts the data provided in `in_out` in-place.
750    /// Returns a references to the decrypted data.
751    ///
752    /// If `DecryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
753    /// of the block length.
754    ///
755    /// # Errors
756    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
757    ///   and `in_out.len()` is not. Also returned if decryption fails.
758    pub fn decrypt<'in_out>(
759        &self,
760        in_out: &'in_out mut [u8],
761        context: DecryptionContext,
762    ) -> Result<&'in_out mut [u8], Unspecified> {
763        decrypt(self.algorithm, &self.key, self.mode, in_out, context)
764    }
765}
766
767impl Debug for DecryptingKey {
768    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
769        f.debug_struct("DecryptingKey")
770            .field("algorithm", &self.algorithm)
771            .field("mode", &self.mode)
772            .finish_non_exhaustive()
773    }
774}
775
776fn encrypt(
777    algorithm: &Algorithm,
778    key: &SymmetricCipherKey,
779    mode: OperatingMode,
780    in_out: &mut [u8],
781    context: EncryptionContext,
782) -> Result<DecryptionContext, Unspecified> {
783    let block_len = algorithm.block_len();
784
785    match mode {
786        OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
787            return Err(Unspecified);
788        }
789        _ => {}
790    }
791
792    match mode {
793        OperatingMode::CBC => match algorithm.id() {
794            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
795                aes::encrypt_cbc_mode(key, context, in_out)
796            }
797        },
798        OperatingMode::CTR => match algorithm.id() {
799            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
800                aes::encrypt_ctr_mode(key, context, in_out)
801            }
802        },
803        // TODO: Hopefully support CFB1, and CFB8
804        OperatingMode::CFB128 => match algorithm.id() {
805            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
806                aes::encrypt_cfb_mode(key, mode, context, in_out)
807            }
808        },
809        OperatingMode::ECB => match algorithm.id() {
810            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
811                aes::encrypt_ecb_mode(key, context, in_out)
812            }
813        },
814    }
815}
816
817fn decrypt<'in_out>(
818    algorithm: &'static Algorithm,
819    key: &SymmetricCipherKey,
820    mode: OperatingMode,
821    in_out: &'in_out mut [u8],
822    context: DecryptionContext,
823) -> Result<&'in_out mut [u8], Unspecified> {
824    let block_len = algorithm.block_len();
825
826    match mode {
827        OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
828            return Err(Unspecified);
829        }
830        _ => {}
831    }
832
833    match mode {
834        OperatingMode::CBC => match algorithm.id() {
835            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
836                aes::decrypt_cbc_mode(key, context, in_out)
837            }
838        },
839        OperatingMode::CTR => match algorithm.id() {
840            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
841                aes::decrypt_ctr_mode(key, context, in_out)
842            }
843        },
844        // TODO: Hopefully support CFB1, and CFB8
845        OperatingMode::CFB128 => match algorithm.id() {
846            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
847                aes::decrypt_cfb_mode(key, mode, context, in_out)
848            }
849        },
850        OperatingMode::ECB => match algorithm.id() {
851            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
852                aes::decrypt_ecb_mode(key, context, in_out)
853            }
854        },
855    }
856}
857
858#[cfg(test)]
859mod tests {
860    use super::*;
861    use crate::test::from_hex;
862
863    #[cfg(feature = "fips")]
864    mod fips;
865
866    #[test]
867    fn test_debug() {
868        {
869            let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
870            let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
871            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
872        }
873
874        {
875            let aes_256_key_bytes =
876                from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
877                    .unwrap();
878            let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
879            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
880        }
881
882        {
883            let key_bytes = &[0u8; 16];
884            let key = PaddedBlockEncryptingKey::cbc_pkcs7(
885                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
886            )
887            .unwrap();
888            assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
889            let mut data = vec![0u8; 16];
890            let context = key.encrypt(&mut data).unwrap();
891            assert_eq!("Iv128", format!("{context:?}"));
892            let key = PaddedBlockDecryptingKey::cbc_pkcs7(
893                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
894            )
895            .unwrap();
896            assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
897        }
898
899        {
900            let key_bytes = &[0u8; 16];
901            let key =
902                EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
903            assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
904            let mut data = vec![0u8; 16];
905            let context = key.encrypt(&mut data).unwrap();
906            assert_eq!("Iv128", format!("{context:?}"));
907            let key =
908                DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
909            assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
910        }
911    }
912
913    fn helper_test_cipher_n_bytes(
914        key: &[u8],
915        alg: &'static Algorithm,
916        mode: OperatingMode,
917        n: usize,
918    ) {
919        let mut input: Vec<u8> = Vec::with_capacity(n);
920        for i in 0..n {
921            let byte: u8 = i.try_into().unwrap();
922            input.push(byte);
923        }
924
925        let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
926        let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
927
928        let mut in_out = input.clone();
929        let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
930
931        if n > 5 {
932            // There's no more than a 1 in 2^48 chance that this will fail randomly
933            assert_ne!(input.as_slice(), in_out);
934        }
935
936        let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
937        let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
938
939        let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
940        assert_eq!(input.as_slice(), plaintext);
941    }
942
943    #[test]
944    fn test_aes_128_ctr() {
945        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
946        for i in 0..=50 {
947            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
948        }
949    }
950
951    #[test]
952    fn test_aes_128_cfb128() {
953        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
954        for i in 0..=50 {
955            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
956        }
957    }
958
959    #[test]
960    fn test_aes_256_cfb128() {
961        let key =
962            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
963        for i in 0..=50 {
964            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
965        }
966    }
967
968    #[test]
969    fn test_aes_256_ctr() {
970        let key =
971            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
972        for i in 0..=50 {
973            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
974        }
975    }
976
977    #[test]
978    fn test_aes_128_cbc() {
979        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
980        // CBC mode requires input to be a multiple of block size (16 bytes)
981        for i in 0..=3 {
982            let size = i * 16; // Test with 0, 16, 32, 48 bytes
983            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
984        }
985    }
986
987    #[test]
988    fn test_aes_256_cbc() {
989        let key =
990            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
991        // CBC mode requires input to be a multiple of block size (16 bytes)
992        for i in 0..=3 {
993            let size = i * 16; // Test with 0, 16, 32, 48 bytes
994            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
995        }
996    }
997
998    #[test]
999    fn test_aes_128_ecb() {
1000        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1001        _ = key;
1002    }
1003
1004    macro_rules! cipher_kat {
1005        ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1006            #[test]
1007            fn $name() {
1008                let key = from_hex($key).unwrap();
1009                let input = from_hex($plaintext).unwrap();
1010                let expected_ciphertext = from_hex($ciphertext).unwrap();
1011                let mut iv = from_hex($iv).unwrap();
1012                let iv = {
1013                    let slice = iv.as_mut_slice();
1014                    let mut iv = [0u8; $iv.len() / 2];
1015                    {
1016                        let x = iv.as_mut_slice();
1017                        x.copy_from_slice(slice);
1018                    }
1019                    iv
1020                };
1021
1022                let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1023
1024                let alg = $alg;
1025
1026                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1027
1028                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1029
1030                let mut in_out = input.clone();
1031
1032                let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1033
1034                assert_eq!(expected_ciphertext, in_out);
1035
1036                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1037                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1038
1039                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1040                assert_eq!(input.as_slice(), plaintext);
1041            }
1042        };
1043        ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1044            #[test]
1045            fn $name() {
1046                let key = from_hex($key).unwrap();
1047                let input = from_hex($plaintext).unwrap();
1048                let expected_ciphertext = from_hex($ciphertext).unwrap();
1049
1050                let alg = $alg;
1051
1052                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1053
1054                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1055
1056                let mut in_out = input.clone();
1057
1058                let context = encrypting_key
1059                    .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1060                    .unwrap();
1061
1062                assert_eq!(expected_ciphertext, in_out);
1063
1064                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1065                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1066
1067                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1068                assert_eq!(input.as_slice(), plaintext);
1069            }
1070        };
1071    }
1072
1073    cipher_kat!(
1074        test_iv_aes_128_ctr_16_bytes,
1075        &AES_128,
1076        OperatingMode::CTR,
1077        "000102030405060708090a0b0c0d0e0f",
1078        "00000000000000000000000000000000",
1079        "00112233445566778899aabbccddeeff",
1080        "c6b01904c3da3df5e7d62bd96d153686"
1081    );
1082
1083    cipher_kat!(
1084        test_iv_aes_256_ctr_15_bytes,
1085        &AES_256,
1086        OperatingMode::CTR,
1087        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1088        "00000000000000000000000000000000",
1089        "00112233445566778899aabbccddee",
1090        "f28122856e1cf9a7216a30d111f399"
1091    );
1092
1093    cipher_kat!(
1094        test_openssl_aes_128_ctr_15_bytes,
1095        &AES_128,
1096        OperatingMode::CTR,
1097        "244828580821c1652582c76e34d299f5",
1098        "093145d5af233f46072a5eb5adc11aa1",
1099        "3ee38cec171e6cf466bf0df98aa0e1",
1100        "bd7d928f60e3422d96b3f8cd614eb2"
1101    );
1102
1103    cipher_kat!(
1104        test_openssl_aes_256_ctr_15_bytes,
1105        &AES_256,
1106        OperatingMode::CTR,
1107        "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1108        "f028ecb053f801102d11fccc9d303a27",
1109        "eca7285d19f3c20e295378460e8729",
1110        "b5098e5e788de6ac2f2098eb2fc6f8"
1111    );
1112
1113    cipher_kat!(
1114        test_sp800_38a_cfb128_aes128,
1115        &AES_128,
1116        OperatingMode::CFB128,
1117        "2b7e151628aed2a6abf7158809cf4f3c",
1118        "000102030405060708090a0b0c0d0e0f",
1119        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1120        "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1121    );
1122
1123    cipher_kat!(
1124        test_sp800_38a_cfb128_aes256,
1125        &AES_256,
1126        OperatingMode::CFB128,
1127        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1128        "000102030405060708090a0b0c0d0e0f",
1129        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1130        "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1131    );
1132
1133    cipher_kat!(
1134        test_sp800_38a_ecb_aes128,
1135        &AES_128,
1136        OperatingMode::ECB,
1137        "2b7e151628aed2a6abf7158809cf4f3c",
1138        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1139        "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1140    );
1141
1142    cipher_kat!(
1143        test_sp800_38a_ecb_aes256,
1144        &AES_256,
1145        OperatingMode::ECB,
1146        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1147        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1148        "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1149    );
1150
1151    cipher_kat!(
1152        test_sp800_38a_cbc_aes128,
1153        &AES_128,
1154        OperatingMode::CBC,
1155        "2b7e151628aed2a6abf7158809cf4f3c",
1156        "000102030405060708090a0b0c0d0e0f",
1157        "6bc1bee22e409f96e93d7e117393172a",
1158        "7649abac8119b246cee98e9b12e9197d"
1159    );
1160
1161    cipher_kat!(
1162        test_sp800_38a_cbc_aes256,
1163        &AES_256,
1164        OperatingMode::CBC,
1165        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1166        "000102030405060708090a0b0c0d0e0f",
1167        "6bc1bee22e409f96e93d7e117393172a",
1168        "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1169    );
1170
1171    cipher_kat!(
1172        test_sp800_38a_cbc_aes128_multi_block,
1173        &AES_128,
1174        OperatingMode::CBC,
1175        "2b7e151628aed2a6abf7158809cf4f3c",
1176        "000102030405060708090a0b0c0d0e0f",
1177        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1178        "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1179    );
1180
1181    cipher_kat!(
1182        test_sp800_38a_cbc_aes256_multi_block,
1183        &AES_256,
1184        OperatingMode::CBC,
1185        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1186        "000102030405060708090a0b0c0d0e0f",
1187        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1188        "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1189    );
1190}