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 => {
787            if in_out.len() % block_len != 0 {
788                return Err(Unspecified);
789            }
790        }
791        _ => {}
792    }
793
794    match mode {
795        OperatingMode::CBC => match algorithm.id() {
796            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
797                aes::encrypt_cbc_mode(key, context, in_out)
798            }
799        },
800        OperatingMode::CTR => match algorithm.id() {
801            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
802                aes::encrypt_ctr_mode(key, context, in_out)
803            }
804        },
805        // TODO: Hopefully support CFB1, and CFB8
806        OperatingMode::CFB128 => match algorithm.id() {
807            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
808                aes::encrypt_cfb_mode(key, mode, context, in_out)
809            }
810        },
811        OperatingMode::ECB => match algorithm.id() {
812            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
813                aes::encrypt_ecb_mode(key, context, in_out)
814            }
815        },
816    }
817}
818
819fn decrypt<'in_out>(
820    algorithm: &'static Algorithm,
821    key: &SymmetricCipherKey,
822    mode: OperatingMode,
823    in_out: &'in_out mut [u8],
824    context: DecryptionContext,
825) -> Result<&'in_out mut [u8], Unspecified> {
826    let block_len = algorithm.block_len();
827
828    match mode {
829        OperatingMode::CBC | OperatingMode::ECB => {
830            if in_out.len() % block_len != 0 {
831                return Err(Unspecified);
832            }
833        }
834        _ => {}
835    }
836
837    match mode {
838        OperatingMode::CBC => match algorithm.id() {
839            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
840                aes::decrypt_cbc_mode(key, context, in_out)
841            }
842        },
843        OperatingMode::CTR => match algorithm.id() {
844            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
845                aes::decrypt_ctr_mode(key, context, in_out)
846            }
847        },
848        // TODO: Hopefully support CFB1, and CFB8
849        OperatingMode::CFB128 => match algorithm.id() {
850            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
851                aes::decrypt_cfb_mode(key, mode, context, in_out)
852            }
853        },
854        OperatingMode::ECB => match algorithm.id() {
855            AlgorithmId::Aes128 | AlgorithmId::Aes192 | AlgorithmId::Aes256 => {
856                aes::decrypt_ecb_mode(key, context, in_out)
857            }
858        },
859    }
860}
861
862#[cfg(test)]
863mod tests {
864    use super::*;
865    use crate::test::from_hex;
866
867    #[cfg(feature = "fips")]
868    mod fips;
869
870    #[test]
871    fn test_debug() {
872        {
873            let aes_128_key_bytes = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
874            let cipher_key = UnboundCipherKey::new(&AES_128, aes_128_key_bytes.as_slice()).unwrap();
875            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 } }", format!("{cipher_key:?}"));
876        }
877
878        {
879            let aes_256_key_bytes =
880                from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f")
881                    .unwrap();
882            let cipher_key = UnboundCipherKey::new(&AES_256, aes_256_key_bytes.as_slice()).unwrap();
883            assert_eq!("UnboundCipherKey { algorithm: Algorithm { id: Aes256, key_len: 32, block_len: 16 } }", format!("{cipher_key:?}"));
884        }
885
886        {
887            let key_bytes = &[0u8; 16];
888            let key = PaddedBlockEncryptingKey::cbc_pkcs7(
889                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
890            )
891            .unwrap();
892            assert_eq!("PaddedBlockEncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
893            let mut data = vec![0u8; 16];
894            let context = key.encrypt(&mut data).unwrap();
895            assert_eq!("Iv128", format!("{context:?}"));
896            let key = PaddedBlockDecryptingKey::cbc_pkcs7(
897                UnboundCipherKey::new(&AES_128, key_bytes).unwrap(),
898            )
899            .unwrap();
900            assert_eq!("PaddedBlockDecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CBC, padding: PKCS7, .. }", format!("{key:?}"));
901        }
902
903        {
904            let key_bytes = &[0u8; 16];
905            let key =
906                EncryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
907            assert_eq!("EncryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
908            let mut data = vec![0u8; 16];
909            let context = key.encrypt(&mut data).unwrap();
910            assert_eq!("Iv128", format!("{context:?}"));
911            let key =
912                DecryptingKey::ctr(UnboundCipherKey::new(&AES_128, key_bytes).unwrap()).unwrap();
913            assert_eq!("DecryptingKey { algorithm: Algorithm { id: Aes128, key_len: 16, block_len: 16 }, mode: CTR, .. }", format!("{key:?}"));
914        }
915    }
916
917    fn helper_test_cipher_n_bytes(
918        key: &[u8],
919        alg: &'static Algorithm,
920        mode: OperatingMode,
921        n: usize,
922    ) {
923        let mut input: Vec<u8> = Vec::with_capacity(n);
924        for i in 0..n {
925            let byte: u8 = i.try_into().unwrap();
926            input.push(byte);
927        }
928
929        let cipher_key = UnboundCipherKey::new(alg, key).unwrap();
930        let encrypting_key = EncryptingKey::new(cipher_key, mode).unwrap();
931
932        let mut in_out = input.clone();
933        let decrypt_iv = encrypting_key.encrypt(&mut in_out).unwrap();
934
935        if n > 5 {
936            // There's no more than a 1 in 2^48 chance that this will fail randomly
937            assert_ne!(input.as_slice(), in_out);
938        }
939
940        let cipher_key2 = UnboundCipherKey::new(alg, key).unwrap();
941        let decrypting_key = DecryptingKey::new(cipher_key2, mode).unwrap();
942
943        let plaintext = decrypting_key.decrypt(&mut in_out, decrypt_iv).unwrap();
944        assert_eq!(input.as_slice(), plaintext);
945    }
946
947    #[test]
948    fn test_aes_128_ctr() {
949        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
950        for i in 0..=50 {
951            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CTR, i);
952        }
953    }
954
955    #[test]
956    fn test_aes_128_cfb128() {
957        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
958        for i in 0..=50 {
959            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CFB128, i);
960        }
961    }
962
963    #[test]
964    fn test_aes_256_cfb128() {
965        let key =
966            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
967        for i in 0..=50 {
968            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CFB128, i);
969        }
970    }
971
972    #[test]
973    fn test_aes_256_ctr() {
974        let key =
975            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
976        for i in 0..=50 {
977            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CTR, i);
978        }
979    }
980
981    #[test]
982    fn test_aes_128_cbc() {
983        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
984        // CBC mode requires input to be a multiple of block size (16 bytes)
985        for i in 0..=3 {
986            let size = i * 16; // Test with 0, 16, 32, 48 bytes
987            helper_test_cipher_n_bytes(key.as_slice(), &AES_128, OperatingMode::CBC, size);
988        }
989    }
990
991    #[test]
992    fn test_aes_256_cbc() {
993        let key =
994            from_hex("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f").unwrap();
995        // CBC mode requires input to be a multiple of block size (16 bytes)
996        for i in 0..=3 {
997            let size = i * 16; // Test with 0, 16, 32, 48 bytes
998            helper_test_cipher_n_bytes(key.as_slice(), &AES_256, OperatingMode::CBC, size);
999        }
1000    }
1001
1002    #[test]
1003    fn test_aes_128_ecb() {
1004        let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap();
1005        _ = key;
1006    }
1007
1008    macro_rules! cipher_kat {
1009        ($name:ident, $alg:expr, $mode:expr, $key:literal, $iv: literal, $plaintext:literal, $ciphertext:literal) => {
1010            #[test]
1011            fn $name() {
1012                let key = from_hex($key).unwrap();
1013                let input = from_hex($plaintext).unwrap();
1014                let expected_ciphertext = from_hex($ciphertext).unwrap();
1015                let mut iv = from_hex($iv).unwrap();
1016                let iv = {
1017                    let slice = iv.as_mut_slice();
1018                    let mut iv = [0u8; $iv.len() / 2];
1019                    {
1020                        let x = iv.as_mut_slice();
1021                        x.copy_from_slice(slice);
1022                    }
1023                    iv
1024                };
1025
1026                let ec = EncryptionContext::Iv128(FixedLength::from(iv));
1027
1028                let alg = $alg;
1029
1030                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1031
1032                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1033
1034                let mut in_out = input.clone();
1035
1036                let context = encrypting_key.less_safe_encrypt(&mut in_out, ec).unwrap();
1037
1038                assert_eq!(expected_ciphertext, in_out);
1039
1040                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1041                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1042
1043                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1044                assert_eq!(input.as_slice(), plaintext);
1045            }
1046        };
1047        ($name:ident, $alg:expr, $mode:expr, $key:literal, $plaintext:literal, $ciphertext:literal) => {
1048            #[test]
1049            fn $name() {
1050                let key = from_hex($key).unwrap();
1051                let input = from_hex($plaintext).unwrap();
1052                let expected_ciphertext = from_hex($ciphertext).unwrap();
1053
1054                let alg = $alg;
1055
1056                let unbound_key = UnboundCipherKey::new(alg, &key).unwrap();
1057
1058                let encrypting_key = EncryptingKey::new(unbound_key, $mode).unwrap();
1059
1060                let mut in_out = input.clone();
1061
1062                let context = encrypting_key
1063                    .less_safe_encrypt(&mut in_out, EncryptionContext::None)
1064                    .unwrap();
1065
1066                assert_eq!(expected_ciphertext, in_out);
1067
1068                let unbound_key2 = UnboundCipherKey::new(alg, &key).unwrap();
1069                let decrypting_key = DecryptingKey::new(unbound_key2, $mode).unwrap();
1070
1071                let plaintext = decrypting_key.decrypt(&mut in_out, context).unwrap();
1072                assert_eq!(input.as_slice(), plaintext);
1073            }
1074        };
1075    }
1076
1077    cipher_kat!(
1078        test_iv_aes_128_ctr_16_bytes,
1079        &AES_128,
1080        OperatingMode::CTR,
1081        "000102030405060708090a0b0c0d0e0f",
1082        "00000000000000000000000000000000",
1083        "00112233445566778899aabbccddeeff",
1084        "c6b01904c3da3df5e7d62bd96d153686"
1085    );
1086
1087    cipher_kat!(
1088        test_iv_aes_256_ctr_15_bytes,
1089        &AES_256,
1090        OperatingMode::CTR,
1091        "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
1092        "00000000000000000000000000000000",
1093        "00112233445566778899aabbccddee",
1094        "f28122856e1cf9a7216a30d111f399"
1095    );
1096
1097    cipher_kat!(
1098        test_openssl_aes_128_ctr_15_bytes,
1099        &AES_128,
1100        OperatingMode::CTR,
1101        "244828580821c1652582c76e34d299f5",
1102        "093145d5af233f46072a5eb5adc11aa1",
1103        "3ee38cec171e6cf466bf0df98aa0e1",
1104        "bd7d928f60e3422d96b3f8cd614eb2"
1105    );
1106
1107    cipher_kat!(
1108        test_openssl_aes_256_ctr_15_bytes,
1109        &AES_256,
1110        OperatingMode::CTR,
1111        "0857db8240ea459bdf660b4cced66d1f2d3734ff2de7b81e92740e65e7cc6a1d",
1112        "f028ecb053f801102d11fccc9d303a27",
1113        "eca7285d19f3c20e295378460e8729",
1114        "b5098e5e788de6ac2f2098eb2fc6f8"
1115    );
1116
1117    cipher_kat!(
1118        test_sp800_38a_cfb128_aes128,
1119        &AES_128,
1120        OperatingMode::CFB128,
1121        "2b7e151628aed2a6abf7158809cf4f3c",
1122        "000102030405060708090a0b0c0d0e0f",
1123        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1124        "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf187a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6"
1125    );
1126
1127    cipher_kat!(
1128        test_sp800_38a_cfb128_aes256,
1129        &AES_256,
1130        OperatingMode::CFB128,
1131        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1132        "000102030405060708090a0b0c0d0e0f",
1133        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1134        "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8267ae2f975a385741ab9cef82031623d55b1e471"
1135    );
1136
1137    cipher_kat!(
1138        test_sp800_38a_ecb_aes128,
1139        &AES_128,
1140        OperatingMode::ECB,
1141        "2b7e151628aed2a6abf7158809cf4f3c",
1142        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1143        "3ad77bb40d7a3660a89ecaf32466ef97f5d3d58503b9699de785895a96fdbaaf43b1cd7f598ece23881b00e3ed0306887b0c785e27e8ad3f8223207104725dd4"
1144    );
1145
1146    cipher_kat!(
1147        test_sp800_38a_ecb_aes256,
1148        &AES_256,
1149        OperatingMode::ECB,
1150        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1151        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1152        "f3eed1bdb5d2a03c064b5a7e3db181f8591ccb10d410ed26dc5ba74a31362870b6ed21b99ca6f4f9f153e7b1beafed1d23304b7a39f9f3ff067d8d8f9e24ecc7"
1153    );
1154
1155    cipher_kat!(
1156        test_sp800_38a_cbc_aes128,
1157        &AES_128,
1158        OperatingMode::CBC,
1159        "2b7e151628aed2a6abf7158809cf4f3c",
1160        "000102030405060708090a0b0c0d0e0f",
1161        "6bc1bee22e409f96e93d7e117393172a",
1162        "7649abac8119b246cee98e9b12e9197d"
1163    );
1164
1165    cipher_kat!(
1166        test_sp800_38a_cbc_aes256,
1167        &AES_256,
1168        OperatingMode::CBC,
1169        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1170        "000102030405060708090a0b0c0d0e0f",
1171        "6bc1bee22e409f96e93d7e117393172a",
1172        "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
1173    );
1174
1175    cipher_kat!(
1176        test_sp800_38a_cbc_aes128_multi_block,
1177        &AES_128,
1178        OperatingMode::CBC,
1179        "2b7e151628aed2a6abf7158809cf4f3c",
1180        "000102030405060708090a0b0c0d0e0f",
1181        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1182        "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e222295163ff1caa1681fac09120eca307586e1a7"
1183    );
1184
1185    cipher_kat!(
1186        test_sp800_38a_cbc_aes256_multi_block,
1187        &AES_256,
1188        OperatingMode::CBC,
1189        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
1190        "000102030405060708090a0b0c0d0e0f",
1191        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
1192        "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e26304231461b2eb05e2c39be9fcda6c19078c6a9d1b"
1193    );
1194}