1use std::result::Result;
7
8use crate::crypto::provider::provider;
9
10#[derive(Debug, thiserror::Error)]
11pub enum EncryptionError {
12 #[error("The key or IV is the wrong length.")]
13 BadKeyOrIv,
14 #[error("Padding error during encryption.")]
15 BadPadding,
16}
17
18#[derive(Debug, thiserror::Error)]
19pub enum DecryptionError {
20 #[error("The key or IV is the wrong length.")]
21 BadKeyOrIv,
22 #[error(
23 "These cases should not be distinguished; message corruption can cause either problem."
24 )]
25 BadCiphertext(&'static str),
26}
27
28pub fn aes_256_cbc_encrypt_into(
29 ptext: &[u8],
30 key: &[u8],
31 iv: &[u8],
32 output: &mut Vec<u8>,
33) -> Result<(), EncryptionError> {
34 let key: &[u8; 32] = key.try_into().map_err(|_| EncryptionError::BadKeyOrIv)?;
35 let iv: &[u8; 16] = iv.try_into().map_err(|_| EncryptionError::BadKeyOrIv)?;
36 provider()
37 .aes_256_cbc_encrypt(key, iv, ptext, output)
38 .map_err(|_| EncryptionError::BadPadding)
39}
40
41pub fn aes_256_cbc_decrypt_into(
43 ctext: &[u8],
44 key: &[u8],
45 iv: &[u8],
46 output: &mut Vec<u8>,
47) -> Result<(), DecryptionError> {
48 let key: &[u8; 32] = key.try_into().map_err(|_| DecryptionError::BadKeyOrIv)?;
49 let iv: &[u8; 16] = iv.try_into().map_err(|_| DecryptionError::BadKeyOrIv)?;
50 provider()
51 .aes_256_cbc_decrypt(key, iv, ctext, output)
52 .map_err(|_| DecryptionError::BadCiphertext("failed to decrypt"))
53}
54
55pub fn aes_256_cbc_decrypt_in_place(
57 buffer: &mut Vec<u8>,
58 key: &[u8],
59 iv: &[u8],
60) -> Result<(), DecryptionError> {
61 let key: &[u8; 32] = key.try_into().map_err(|_| DecryptionError::BadKeyOrIv)?;
62 let iv: &[u8; 16] = iv.try_into().map_err(|_| DecryptionError::BadKeyOrIv)?;
63 provider()
64 .aes_256_cbc_decrypt_in_place(key, iv, buffer)
65 .map_err(|_| DecryptionError::BadCiphertext("failed to decrypt"))
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_encrypt_into_appends_to_existing_buffer() {
74 let plaintext = b"test message";
75 let key = [3u8; 32];
76 let iv = [4u8; 16];
77
78 let mut buffer = vec![1, 2, 3, 4]; let initial_len = buffer.len();
80
81 aes_256_cbc_encrypt_into(plaintext, &key, &iv, &mut buffer).expect("Encryption failed");
82
83 assert_eq!(&buffer[..initial_len], &[1, 2, 3, 4]);
85
86 let encrypted_part = &buffer[initial_len..];
88 let mut decrypted = Vec::new();
89 aes_256_cbc_decrypt_into(encrypted_part, &key, &iv, &mut decrypted)
90 .expect("Decryption failed");
91 assert_eq!(decrypted, plaintext);
92 }
93
94 #[test]
96 fn test_aes_cbc_roundtrip() {
97 let key = [0x42u8; 32];
98 let iv = [0x11u8; 16];
99 let plaintext = b"hello world, this is a roundtrip test!";
100
101 let mut ciphertext = Vec::new();
102 aes_256_cbc_encrypt_into(plaintext, &key, &iv, &mut ciphertext).unwrap();
103
104 assert_ne!(&ciphertext[..], &plaintext[..]);
106
107 let mut decrypted = Vec::new();
108 aes_256_cbc_decrypt_into(&ciphertext, &key, &iv, &mut decrypted).unwrap();
109 assert_eq!(decrypted, plaintext);
110 }
111
112 #[test]
113 fn test_aes_cbc_in_place_roundtrip_reuses_allocation() {
114 let key = [0x42u8; 32];
115 let iv = [0x11u8; 16];
116 let plaintext = b"caller-owned ciphertext allocation";
117
118 let mut buffer = Vec::new();
119 aes_256_cbc_encrypt_into(plaintext, &key, &iv, &mut buffer).unwrap();
120 let allocation = buffer.as_ptr();
121
122 aes_256_cbc_decrypt_in_place(&mut buffer, &key, &iv).unwrap();
123
124 assert_eq!(buffer, plaintext);
125 assert_eq!(buffer.as_ptr(), allocation);
126 }
127
128 #[test]
137 fn test_aes_256_cbc_nist_vector() {
138 let key: [u8; 32] = [
139 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d,
140 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3,
141 0x09, 0x14, 0xdf, 0xf4,
142 ];
143 let iv: [u8; 16] = [
144 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
145 0x0e, 0x0f,
146 ];
147 let plaintext: [u8; 16] = [
148 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93,
149 0x17, 0x2a,
150 ];
151 let expected_ct_block: [u8; 16] = [
152 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b,
153 0xfb, 0xd6,
154 ];
155
156 let mut ciphertext = Vec::new();
157 aes_256_cbc_encrypt_into(&plaintext, &key, &iv, &mut ciphertext).unwrap();
158
159 assert_eq!(ciphertext.len(), 32, "16-byte input + PKCS7 = 32 bytes");
161 assert_eq!(
162 &ciphertext[..16],
163 &expected_ct_block,
164 "First ciphertext block must match NIST vector"
165 );
166
167 let mut decrypted = Vec::new();
169 aes_256_cbc_decrypt_into(&ciphertext, &key, &iv, &mut decrypted).unwrap();
170 assert_eq!(decrypted, plaintext);
171 }
172
173 #[test]
175 fn test_aes_cbc_empty_plaintext() {
176 let key = [0x42u8; 32];
177 let iv = [0x11u8; 16];
178
179 let mut ciphertext = Vec::new();
180 aes_256_cbc_encrypt_into(b"", &key, &iv, &mut ciphertext).unwrap();
181
182 assert_eq!(ciphertext.len(), 16);
184
185 let mut decrypted = Vec::new();
186 aes_256_cbc_decrypt_into(&ciphertext, &key, &iv, &mut decrypted).unwrap();
187 assert!(decrypted.is_empty());
188 }
189
190 #[test]
192 fn test_aes_cbc_exact_block_boundary() {
193 let key = [0x42u8; 32];
194 let iv = [0x11u8; 16];
195 let plaintext = [0xAA; 16]; let mut ciphertext = Vec::new();
198 aes_256_cbc_encrypt_into(&plaintext, &key, &iv, &mut ciphertext).unwrap();
199
200 assert_eq!(ciphertext.len(), 32);
202
203 let mut decrypted = Vec::new();
204 aes_256_cbc_decrypt_into(&ciphertext, &key, &iv, &mut decrypted).unwrap();
205 assert_eq!(decrypted, plaintext);
206 }
207
208 #[test]
210 fn test_aes_cbc_decrypt_wrong_key() {
211 let key = [0x42u8; 32];
212 let wrong_key = [0x43u8; 32];
213 let iv = [0x11u8; 16];
214 let plaintext = b"secret message";
215
216 let mut ciphertext = Vec::new();
217 aes_256_cbc_encrypt_into(plaintext, &key, &iv, &mut ciphertext).unwrap();
218
219 let mut decrypted = Vec::new();
220 let result = aes_256_cbc_decrypt_into(&ciphertext, &wrong_key, &iv, &mut decrypted);
221 assert!(result.is_err());
222 }
223
224 #[test]
226 fn test_aes_cbc_decrypt_bad_ciphertext_length() {
227 let key = [0x42u8; 32];
228 let iv = [0x11u8; 16];
229
230 let mut output = Vec::new();
232 let result = aes_256_cbc_decrypt_into(&[], &key, &iv, &mut output);
233 assert!(result.is_err());
234
235 let bad_ct = vec![0xAA; 15];
237 let result = aes_256_cbc_decrypt_into(&bad_ct, &key, &iv, &mut output);
238 assert!(result.is_err());
239
240 let bad_ct = vec![0xBB; 17];
242 let result = aes_256_cbc_decrypt_into(&bad_ct, &key, &iv, &mut output);
243 assert!(result.is_err());
244 }
245}