encryption/encryptor/
aes256cbc.rs1use aes::Aes256;
7use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::Pkcs7};
8use cbc::{Decryptor, Encryptor};
9use rand_core::{OsRng, RngCore};
10
11use crate::contract::{Identified, SymmetricCipher};
12use crate::error::{Error, Result};
13use crate::internal::etm;
14use crate::key::Key;
15
16const LABEL: &str = "AES-256-CBC";
17const IV_LEN: usize = 16;
18
19#[derive(Debug)]
21pub struct Aes256CbcEncryptor {
22 key: Key<32>,
23}
24
25impl Aes256CbcEncryptor {
26 pub const IDENTIFIER: &'static str = "aes-256-cbc-hmac";
27
28 pub fn new(key: [u8; 32]) -> Self {
29 Self { key: Key::new(key) }
30 }
31
32 pub fn from_slice(key: &[u8]) -> Result<Self> {
33 Ok(Self {
34 key: Key::from_slice(key, LABEL)?,
35 })
36 }
37}
38
39impl Identified for Aes256CbcEncryptor {
40 fn identifier(&self) -> &str {
41 Self::IDENTIFIER
42 }
43}
44
45impl SymmetricCipher for Aes256CbcEncryptor {
46 fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>> {
47 let mut iv = [0u8; IV_LEN];
48 OsRng.fill_bytes(&mut iv);
49
50 let ciphertext = Encryptor::<Aes256>::new_from_slices(self.key.as_bytes(), &iv)
51 .expect("key and iv lengths are fixed")
52 .encrypt_padded_vec_mut::<Pkcs7>(plaintext);
53
54 Ok(etm::pack(&iv, &ciphertext, self.key.as_bytes()))
55 }
56
57 fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
58 let (iv, body) = etm::unpack_and_verify(ciphertext, IV_LEN, self.key.as_bytes(), LABEL)?;
59
60 Decryptor::<Aes256>::new_from_slices(self.key.as_bytes(), iv)
61 .expect("key and iv lengths were verified")
62 .decrypt_padded_vec_mut::<Pkcs7>(body)
63 .map_err(|_| Error::DecryptionFailed { label: LABEL })
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn roundtrip_even_for_empty_plaintext() {
73 let encryptor = Aes256CbcEncryptor::new([5u8; 32]);
74 for plaintext in [
75 b"".as_slice(),
76 b"x",
77 b"0123456789abcdef",
78 b"0123456789abcdefg",
79 ] {
80 let blob = encryptor.encrypt(plaintext).unwrap();
81 assert_eq!(encryptor.decrypt(&blob).unwrap(), plaintext);
82 }
83 }
84
85 #[test]
86 fn tampered_blob_fails_mac_before_decrypt() {
87 let encryptor = Aes256CbcEncryptor::new([5u8; 32]);
88 let mut blob = encryptor.encrypt(b"secret").unwrap();
89 let last = blob.len() - 1;
90 blob[last] ^= 0x01;
91 assert_eq!(
92 encryptor.decrypt(&blob).unwrap_err(),
93 Error::MacVerificationFailed { label: LABEL }
94 );
95 }
96
97 #[test]
98 fn wrong_key_fails_mac() {
99 let blob = Aes256CbcEncryptor::new([5u8; 32])
100 .encrypt(b"secret")
101 .unwrap();
102 let other = Aes256CbcEncryptor::new([6u8; 32]);
103 assert_eq!(
104 other.decrypt(&blob).unwrap_err(),
105 Error::MacVerificationFailed { label: LABEL }
106 );
107 }
108
109 #[test]
110 fn key_length_is_checked() {
111 assert_eq!(
112 Aes256CbcEncryptor::from_slice(&[0u8; 33]).unwrap_err(),
113 Error::InvalidKeyLength {
114 label: LABEL,
115 expected: 32,
116 got: 33
117 }
118 );
119 }
120}