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        if key_bytes.len() != algorithm.key_len {
491            return Err(Unspecified);
492        }
493        let key_bytes = Buffer::new(key_bytes.to_vec());
494        Ok(UnboundCipherKey {
495            algorithm,
496            key_bytes,
497        })
498    }
499
500    #[inline]
501    #[must_use]
502    /// Returns the algorithm associated with this key.
503    pub fn algorithm(&self) -> &'static Algorithm {
504        self.algorithm
505    }
506}
507
508impl TryInto<SymmetricCipherKey> for UnboundCipherKey {
509    type Error = Unspecified;
510
511    fn try_into(self) -> Result<SymmetricCipherKey, Self::Error> {
512        match self.algorithm.id() {
513            AlgorithmId::Aes128 => SymmetricCipherKey::aes128(self.key_bytes.as_ref()),
514            AlgorithmId::Aes192 => SymmetricCipherKey::aes192(self.key_bytes.as_ref()),
515            AlgorithmId::Aes256 => SymmetricCipherKey::aes256(self.key_bytes.as_ref()),
516        }
517    }
518}
519
520/// A cipher encryption key that does not perform block padding.
521pub struct EncryptingKey {
522    algorithm: &'static Algorithm,
523    key: SymmetricCipherKey,
524    mode: OperatingMode,
525}
526
527impl EncryptingKey {
528    /// Constructs an `EncryptingKey` operating in counter (CTR) mode using the provided key.
529    ///
530    // # FIPS
531    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
532    // * `AES_128`
533    // * `AES_256`
534    //
535    /// # Errors
536    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
537    pub fn ctr(key: UnboundCipherKey) -> Result<Self, Unspecified> {
538        Self::new(key, OperatingMode::CTR)
539    }
540
541    /// Constructs an `EncryptingKey` operating in cipher feedback 128-bit mode (CFB128) using the provided key.
542    ///
543    // # FIPS
544    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
545    // * `AES_128`
546    // * `AES_256`
547    //
548    /// # Errors
549    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
550    pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
551        Self::new(key, OperatingMode::CFB128)
552    }
553
554    /// Constructs an `EncryptingKey` operating in cipher block chaining (CBC) mode using the provided key.
555    ///
556    /// # ☠️ ️️️DANGER ☠️
557    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
558    /// very likely not what you want to use.
559    ///
560    // # FIPS
561    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
562    // * `AES_128`
563    // * `AES_256`
564    //
565    /// # Errors
566    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
567    pub fn cbc(key: UnboundCipherKey) -> Result<Self, Unspecified> {
568        Self::new(key, OperatingMode::CBC)
569    }
570
571    /// Constructs an `EncryptingKey` operating in electronic code book mode (ECB) using the provided key.
572    ///
573    /// # ☠️ ️️️DANGER ☠️
574    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
575    /// very likely not what you want to use.
576    ///
577    // # FIPS
578    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
579    // * `AES_128`
580    // * `AES_256`
581    //
582    /// # Errors
583    /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`.
584    pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
585        Self::new(key, OperatingMode::ECB)
586    }
587
588    #[allow(clippy::unnecessary_wraps)]
589    fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
590        let algorithm = key.algorithm();
591        let key = key.try_into()?;
592        Ok(Self {
593            algorithm,
594            key,
595            mode,
596        })
597    }
598
599    /// Returns the cipher algorithm.
600    #[must_use]
601    pub fn algorithm(&self) -> &Algorithm {
602        self.algorithm
603    }
604
605    /// Returns the cipher operating mode.
606    #[must_use]
607    pub fn mode(&self) -> OperatingMode {
608        self.mode
609    }
610
611    /// Encrypts the data provided in `in_out` in-place.
612    /// Returns a [`DecryptionContext`] with the randomly generated IV that was used to encrypt
613    /// the data provided.
614    ///
615    /// If `EncryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
616    /// of the block length.
617    ///
618    /// # Errors
619    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
620    ///   and `in_out.len()` is not. Otherwise, returned if encryption fails.
621    pub fn encrypt(&self, in_out: &mut [u8]) -> Result<DecryptionContext, Unspecified> {
622        let context = self.algorithm.new_encryption_context(self.mode)?;
623        self.less_safe_encrypt(in_out, context)
624    }
625
626    /// Encrypts the data provided in `in_out` in-place using the provided `EncryptionContext`.
627    /// This is considered "less safe" because the caller could potentially construct
628    /// a `EncryptionContext` from a previously used IV (initialization vector).
629    /// Returns a [`DecryptionContext`] produced from the provided `EncryptionContext`.
630    ///
631    /// If `EncryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
632    /// of the block length.
633    ///
634    /// # Errors
635    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
636    ///   and `in_out.len()` is not. Otherwise returned if encryption fails.
637    pub fn less_safe_encrypt(
638        &self,
639        in_out: &mut [u8],
640        context: EncryptionContext,
641    ) -> Result<DecryptionContext, Unspecified> {
642        if !self
643            .algorithm()
644            .is_valid_encryption_context(self.mode, &context)
645        {
646            return Err(Unspecified);
647        }
648        encrypt(self.algorithm(), &self.key, self.mode, in_out, context)
649    }
650}
651
652impl Debug for EncryptingKey {
653    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
654        f.debug_struct("EncryptingKey")
655            .field("algorithm", self.algorithm)
656            .field("mode", &self.mode)
657            .finish_non_exhaustive()
658    }
659}
660
661/// A cipher decryption key that does not perform block padding.
662pub struct DecryptingKey {
663    algorithm: &'static Algorithm,
664    key: SymmetricCipherKey,
665    mode: OperatingMode,
666}
667
668impl DecryptingKey {
669    /// Constructs a cipher decrypting key operating in counter (CTR) mode using the provided key and context.
670    ///
671    // # FIPS
672    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
673    // * `AES_128`
674    // * `AES_256`
675    //
676    /// # Errors
677    /// * [`Unspecified`]: Returned if there is an error during decryption.
678    pub fn ctr(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
679        Self::new(key, OperatingMode::CTR)
680    }
681
682    /// Constructs a cipher decrypting key operating in cipher feedback 128-bit mode (CFB128) using the provided key and context.
683    ///
684    // # FIPS
685    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
686    // * `AES_128`
687    // * `AES_256`
688    //
689    /// # Errors
690    /// * [`Unspecified`]: Returned if there is an error during decryption.
691    pub fn cfb128(key: UnboundCipherKey) -> Result<Self, Unspecified> {
692        Self::new(key, OperatingMode::CFB128)
693    }
694
695    /// Constructs an `DecryptingKey` operating in cipher block chaining (CBC) mode using the provided key and context.
696    ///
697    /// # ☠️ ️️️DANGER ☠️
698    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
699    /// very likely not what you want to use.
700    ///
701    // # FIPS
702    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
703    // * `AES_128`
704    // * `AES_256`
705    //
706    /// # Errors
707    /// * [`Unspecified`]: Returned if there is an error during decryption.
708    pub fn cbc(key: UnboundCipherKey) -> Result<DecryptingKey, Unspecified> {
709        Self::new(key, OperatingMode::CBC)
710    }
711
712    /// Constructs an `DecryptingKey` operating in electronic code book (ECB) mode using the provided key.
713    ///
714    /// # ☠️ ️️️DANGER ☠️
715    /// Offered for compatibility purposes only. This is an extremely dangerous mode, and
716    /// very likely not what you want to use.
717    ///
718    // # FIPS
719    // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms:
720    // * `AES_128`
721    // * `AES_256`
722    //
723    /// # Errors
724    /// * [`Unspecified`]: Returned if there is an error constructing the `DecryptingKey`.
725    pub fn ecb(key: UnboundCipherKey) -> Result<Self, Unspecified> {
726        Self::new(key, OperatingMode::ECB)
727    }
728
729    #[allow(clippy::unnecessary_wraps)]
730    fn new(key: UnboundCipherKey, mode: OperatingMode) -> Result<Self, Unspecified> {
731        let algorithm = key.algorithm();
732        let key = key.try_into()?;
733        Ok(Self {
734            algorithm,
735            key,
736            mode,
737        })
738    }
739
740    /// Returns the cipher algorithm.
741    #[must_use]
742    pub fn algorithm(&self) -> &Algorithm {
743        self.algorithm
744    }
745
746    /// Returns the cipher operating mode.
747    #[must_use]
748    pub fn mode(&self) -> OperatingMode {
749        self.mode
750    }
751
752    /// Decrypts the data provided in `in_out` in-place.
753    /// Returns a references to the decrypted data.
754    ///
755    /// If `DecryptingKey` is operating in `OperatingMode::ECB`, then `in_out.len()` must be a multiple
756    /// of the block length.
757    ///
758    /// # Errors
759    /// * [`Unspecified`]: Returned if cipher mode requires input to be a multiple of the block length,
760    ///   and `in_out.len()` is not. Also returned if decryption fails.
761    pub fn decrypt<'in_out>(
762        &self,
763        in_out: &'in_out mut [u8],
764        context: DecryptionContext,
765    ) -> Result<&'in_out mut [u8], Unspecified> {
766        decrypt(self.algorithm, &self.key, self.mode, in_out, context)
767    }
768}
769
770impl Debug for DecryptingKey {
771    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
772        f.debug_struct("DecryptingKey")
773            .field("algorithm", &self.algorithm)
774            .field("mode", &self.mode)
775            .finish_non_exhaustive()
776    }
777}
778
779fn encrypt(
780    algorithm: &Algorithm,
781    key: &SymmetricCipherKey,
782    mode: OperatingMode,
783    in_out: &mut [u8],
784    context: EncryptionContext,
785) -> Result<DecryptionContext, Unspecified> {
786    let block_len = algorithm.block_len();
787
788    match mode {
789        OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
790            return Err(Unspecified);
791        }
792        _ => {}
793    }
794
795    match mode {
796        OperatingMode::CBC => match algorithm.id() {
797            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
798                aes::encrypt_cbc_mode(key, context, in_out)
799            }
800        },
801        OperatingMode::CTR => match algorithm.id() {
802            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
803                aes::encrypt_ctr_mode(key, context, in_out)
804            }
805        },
806        // TODO: Hopefully support CFB1, and CFB8
807        OperatingMode::CFB128 => match algorithm.id() {
808            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
809                aes::encrypt_cfb_mode(key, mode, context, in_out)
810            }
811        },
812        OperatingMode::ECB => match algorithm.id() {
813            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
814                aes::encrypt_ecb_mode(key, context, in_out)
815            }
816        },
817    }
818}
819
820fn decrypt<'in_out>(
821    algorithm: &'static Algorithm,
822    key: &SymmetricCipherKey,
823    mode: OperatingMode,
824    in_out: &'in_out mut [u8],
825    context: DecryptionContext,
826) -> Result<&'in_out mut [u8], Unspecified> {
827    let block_len = algorithm.block_len();
828
829    match mode {
830        OperatingMode::CBC | OperatingMode::ECB if in_out.len() % block_len != 0 => {
831            return Err(Unspecified);
832        }
833        _ => {}
834    }
835
836    match mode {
837        OperatingMode::CBC => match algorithm.id() {
838            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
839                aes::decrypt_cbc_mode(key, context, in_out)
840            }
841        },
842        OperatingMode::CTR => match algorithm.id() {
843            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
844                aes::decrypt_ctr_mode(key, context, in_out)
845            }
846        },
847        // TODO: Hopefully support CFB1, and CFB8
848        OperatingMode::CFB128 => match algorithm.id() {
849            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
850                aes::decrypt_cfb_mode(key, mode, context, in_out)
851            }
852        },
853        OperatingMode::ECB => match algorithm.id() {
854            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
855                aes::decrypt_ecb_mode(key, context, in_out)
856            }
857        },
858    }
859}
860
861#[cfg(test)]
862mod tests {
863    use super::*;
864    use crate::test::from_hex;
865
866    #[cfg(feature = "fips")]
867    mod fips;
868
869    #[test]
870    fn test_debug() {
871        {
872            let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
873            let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
874            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
875        }
876
877        {
878            let aes_256_key_bytes =
879                from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
880                    .unwrap();
881            let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
882            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
883        }
884
885        {
886            let key_bytes = &[0u8; 16];
887            let key = PaddedBlockEncryptingKey::cbc_pkcs7(
888                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
889            )
890            .unwrap();
891            assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
892            let mut data = vec![0u8; 16];
893            let context = key.encrypt(&mut data).unwrap();
894            assert_eq!("Iv128", format!("{context:?}"));
895            let key = PaddedBlockDecryptingKey::cbc_pkcs7(
896                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
897            )
898            .unwrap();
899            assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
900        }
901
902        {
903            let key_bytes = &[0u8; 16];
904            let key =
905                EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
906            assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
907            let mut data = vec![0u8; 16];
908            let context = key.encrypt(&mut data).unwrap();
909            assert_eq!("Iv128", format!("{context:?}"));
910            let key =
911                DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
912            assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
913        }
914    }
915
916    fn helper_test_cipher_n_bytes(
917        key: &[u8],
918        alg: &'static Algorithm,
919        mode: OperatingMode,
920        n: usize,
921    ) {
922        let mut input: Vec<u8> = Vec::with_capacity(n);
923        for i in 0..n {
924            let byte: u8 = i.try_into().unwrap();
925            input.push(byte);
926        }
927
928        let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
929        let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
930
931        let mut in_out = input.clone();
932        let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
933
934        if n > 5 {
935            // There's no more than a 1 in 2^48 chance that this will fail randomly
936            assert_ne!(input.as_slice(), in_out);
937        }
938
939        let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
940        let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
941
942        let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
943        assert_eq!(input.as_slice(), plaintext);
944    }
945
946    #[test]
947    fn test_aes_128_ctr() {
948        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
949        for i in 0..=50 {
950            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
951        }
952    }
953
954    #[test]
955    fn test_aes_128_cfb128() {
956        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
957        for i in 0..=50 {
958            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
959        }
960    }
961
962    #[test]
963    fn test_aes_256_cfb128() {
964        let key =
965            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
966        for i in 0..=50 {
967            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
968        }
969    }
970
971    #[test]
972    fn test_aes_256_ctr() {
973        let key =
974            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
975        for i in 0..=50 {
976            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
977        }
978    }
979
980    #[test]
981    fn test_aes_128_cbc() {
982        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
983        // CBC mode requires input to be a multiple of block size (16 bytes)
984        for i in 0..=3 {
985            let size = i * 16; // Test with 0, 16, 32, 48 bytes
986            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
987        }
988    }
989
990    #[test]
991    fn test_aes_256_cbc() {
992        let key =
993            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
994        // CBC mode requires input to be a multiple of block size (16 bytes)
995        for i in 0..=3 {
996            let size = i * 16; // Test with 0, 16, 32, 48 bytes
997            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
998        }
999    }
1000
1001    #[test]
1002    fn test_aes_128_ecb() {
1003        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1004        _ = key;
1005    }
1006
1007    macro_rules! cipher_kat {
1008        ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1009            #[test]
1010            fn $name() {
1011                let key = from_hex($key).unwrap();
1012                let input = from_hex($plaintext).unwrap();
1013                let expected_ciphertext = from_hex($ciphertext).unwrap();
1014                let mut iv = from_hex($iv).unwrap();
1015                let iv = {
1016                    let slice = iv.as_mut_slice();
1017                    let mut iv = [0u8; $iv.len() / 2];
1018                    {
1019                        let x = iv.as_mut_slice();
1020                        x.copy_from_slice(slice);
1021                    }
1022                    iv
1023                };
1024
1025                let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1026
1027                let alg = $alg;
1028
1029                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1030
1031                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1032
1033                let mut in_out = input.clone();
1034
1035                let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1036
1037                assert_eq!(expected_ciphertext, in_out);
1038
1039                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1040                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1041
1042                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1043                assert_eq!(input.as_slice(), plaintext);
1044            }
1045        };
1046        ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1047            #[test]
1048            fn $name() {
1049                let key = from_hex($key).unwrap();
1050                let input = from_hex($plaintext).unwrap();
1051                let expected_ciphertext = from_hex($ciphertext).unwrap();
1052
1053                let alg = $alg;
1054
1055                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1056
1057                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1058
1059                let mut in_out = input.clone();
1060
1061                let context = encrypting_key
1062                    .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1063                    .unwrap();
1064
1065                assert_eq!(expected_ciphertext, in_out);
1066
1067                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1068                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1069
1070                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1071                assert_eq!(input.as_slice(), plaintext);
1072            }
1073        };
1074    }
1075
1076    cipher_kat!(
1077        test_iv_aes_128_ctr_16_bytes,
1078        &AES_128,
1079        OperatingMode::CTR,
1080        "000102030405060708090a0b0c0d0e0f",
1081        "00000000000000000000000000000000",
1082        "00112233445566778899aabbccddeeff",
1083        "c6b01904c3da3df5e7d62bd96d153686"
1084    );
1085
1086    cipher_kat!(
1087        test_iv_aes_256_ctr_15_bytes,
1088        &AES_256,
1089        OperatingMode::CTR,
1090        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1091        "00000000000000000000000000000000",
1092        "00112233445566778899aabbccddee",
1093        "f28122856e1cf9a7216a30d111f399"
1094    );
1095
1096    cipher_kat!(
1097        test_openssl_aes_128_ctr_15_bytes,
1098        &AES_128,
1099        OperatingMode::CTR,
1100        "244828580821c1652582c76e34d299f5",
1101        "093145d5af233f46072a5eb5adc11aa1",
1102        "3ee38cec171e6cf466bf0df98aa0e1",
1103        "bd7d928f60e3422d96b3f8cd614eb2"
1104    );
1105
1106    cipher_kat!(
1107        test_openssl_aes_256_ctr_15_bytes,
1108        &AES_256,
1109        OperatingMode::CTR,
1110        "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1111        "f028ecb053f801102d11fccc9d303a27",
1112        "eca7285d19f3c20e295378460e8729",
1113        "b5098e5e788de6ac2f2098eb2fc6f8"
1114    );
1115
1116    cipher_kat!(
1117        test_sp800_38a_cfb128_aes128,
1118        &AES_128,
1119        OperatingMode::CFB128,
1120        "2b7e151628aed2a6abf7158809cf4f3c",
1121        "000102030405060708090a0b0c0d0e0f",
1122        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1123        "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1124    );
1125
1126    cipher_kat!(
1127        test_sp800_38a_cfb128_aes256,
1128        &AES_256,
1129        OperatingMode::CFB128,
1130        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1131        "000102030405060708090a0b0c0d0e0f",
1132        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1133        "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1134    );
1135
1136    cipher_kat!(
1137        test_sp800_38a_ecb_aes128,
1138        &AES_128,
1139        OperatingMode::ECB,
1140        "2b7e151628aed2a6abf7158809cf4f3c",
1141        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1142        "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1143    );
1144
1145    cipher_kat!(
1146        test_sp800_38a_ecb_aes256,
1147        &AES_256,
1148        OperatingMode::ECB,
1149        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1150        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1151        "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1152    );
1153
1154    cipher_kat!(
1155        test_sp800_38a_cbc_aes128,
1156        &AES_128,
1157        OperatingMode::CBC,
1158        "2b7e151628aed2a6abf7158809cf4f3c",
1159        "000102030405060708090a0b0c0d0e0f",
1160        "6bc1bee22e409f96e93d7e117393172a",
1161        "7649abac8119b246cee98e9b12e9197d"
1162    );
1163
1164    cipher_kat!(
1165        test_sp800_38a_cbc_aes256,
1166        &AES_256,
1167        OperatingMode::CBC,
1168        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1169        "000102030405060708090a0b0c0d0e0f",
1170        "6bc1bee22e409f96e93d7e117393172a",
1171        "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1172    );
1173
1174    cipher_kat!(
1175        test_sp800_38a_cbc_aes128_multi_block,
1176        &AES_128,
1177        OperatingMode::CBC,
1178        "2b7e151628aed2a6abf7158809cf4f3c",
1179        "000102030405060708090a0b0c0d0e0f",
1180        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1181        "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1182    );
1183
1184    cipher_kat!(
1185        test_sp800_38a_cbc_aes256_multi_block,
1186        &AES_256,
1187        OperatingMode::CBC,
1188        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1189        "000102030405060708090a0b0c0d0e0f",
1190        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1191        "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1192    );
1193}