bitwarden_crypto/hazmat/symmetric_encryption/
aes256_cbc.rs1use aes::cipher::{BlockModeDecrypt, KeyIvInit, block_padding::Pkcs7};
11
12use super::SymmetricEncryptionError;
13
14pub(crate) const IV_SIZE: usize = 16;
15pub(crate) const KEY_SIZE: usize = 32;
16
17pub(crate) struct Aes256Cbc;
19
20impl Aes256Cbc {
21 pub(crate) fn decrypt(
23 iv: &[u8; IV_SIZE],
24 ciphertext: &[u8],
25 key: &[u8; KEY_SIZE],
26 ) -> Result<Vec<u8>, SymmetricEncryptionError> {
27 let mut data = ciphertext.to_vec();
29 let decrypted_key_slice = cbc::Decryptor::<aes::Aes256>::new(key.into(), iv.into())
30 .decrypt_padded::<Pkcs7>(&mut data)
31 .map_err(|_| SymmetricEncryptionError::FormatWrong)?;
32
33 let decrypted_len = decrypted_key_slice.len();
36 data.truncate(decrypted_len);
37
38 Ok(data)
39 }
40
41 #[cfg(test)]
43 fn encrypt(iv: &[u8; IV_SIZE], plaintext: &[u8], key: &[u8; KEY_SIZE]) -> Vec<u8> {
44 use aes::cipher::BlockModeEncrypt;
45
46 cbc::Encryptor::<aes::Aes256>::new(key.into(), iv.into())
47 .encrypt_padded_vec::<Pkcs7>(plaintext)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use bitwarden_encoding::B64;
54
55 use super::*;
56
57 const TESTVECTOR_PLAINTEXT: &[u8] = b"Bitwarden SDK test vector";
58 const TESTVECTOR_CIPHERTEXT: &[u8] = &[
59 111, 16, 33, 143, 207, 253, 106, 89, 58, 52, 145, 240, 140, 213, 149, 83, 168, 188, 122,
60 57, 130, 28, 35, 182, 114, 227, 215, 250, 175, 182, 169, 102,
61 ];
62 const TESTVECTOR_KEY: [u8; KEY_SIZE] = [
63 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
64 25, 26, 27, 28, 29, 30, 31,
65 ];
66 const TESTVECTOR_IV: [u8; IV_SIZE] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
67
68 #[test]
69 #[ignore = "Generates test vectors; run manually"]
70 fn generate_test_vectors() {
71 let ciphertext = Aes256Cbc::encrypt(&TESTVECTOR_IV, TESTVECTOR_PLAINTEXT, &TESTVECTOR_KEY);
72 let decrypted = Aes256Cbc::decrypt(&TESTVECTOR_IV, &ciphertext, &TESTVECTOR_KEY).unwrap();
73 assert_eq!(decrypted, TESTVECTOR_PLAINTEXT);
74
75 println!("const TESTVECTOR_CIPHERTEXT: &[u8] = &{ciphertext:?};");
76 }
77
78 #[test]
81 fn test_decrypt_testvector() {
82 let decrypted =
83 Aes256Cbc::decrypt(&TESTVECTOR_IV, TESTVECTOR_CIPHERTEXT, &TESTVECTOR_KEY).unwrap();
84
85 assert_eq!(decrypted, TESTVECTOR_PLAINTEXT);
86 }
87
88 #[test]
89 fn test_encrypt_decrypt_roundtrip() {
90 let plaintext = b"EncryptMe!";
91
92 let encrypted = Aes256Cbc::encrypt(&TESTVECTOR_IV, plaintext, &TESTVECTOR_KEY);
93 let decrypted = Aes256Cbc::decrypt(&TESTVECTOR_IV, &encrypted, &TESTVECTOR_KEY).unwrap();
94
95 assert_eq!(decrypted, plaintext);
96 }
97
98 #[test]
99 fn test_decrypt_aes256() {
100 let data: B64 = ("ByUF8vhyX4ddU9gcooznwA==").parse().unwrap();
101
102 let decrypted =
103 Aes256Cbc::decrypt(&TESTVECTOR_IV, data.as_bytes(), &TESTVECTOR_KEY).unwrap();
104
105 assert_eq!(String::from_utf8(decrypted).unwrap(), "EncryptMe!");
106 }
107
108 #[test]
109 fn test_decrypt_aes256_fails_on_invalid_padding() {
110 let iv = [0u8; IV_SIZE];
111
112 let result = Aes256Cbc::decrypt(&iv, &[0u8; 16], &TESTVECTOR_KEY);
114 assert_eq!(result, Err(SymmetricEncryptionError::FormatWrong));
115 }
116}