1use aes::cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit, block_padding::Pkcs7};
9use hmac::{KeyInit, Mac};
10use hybrid_array::Array;
11use subtle::ConstantTimeEq;
12use typenum::U32;
13
14use crate::{
15 error::Result,
16 util::{PBKDF_SHA256_HMAC_OUT_SIZE, PbkdfSha256Hmac},
17};
18
19#[derive(Debug)]
21pub(crate) struct DecryptError {}
22
23pub(crate) fn decrypt_aes256(
27 iv: &[u8; 16],
28 data: Vec<u8>,
29 key: &Array<u8, U32>,
30) -> Result<Vec<u8>, DecryptError> {
31 let mut data = data;
33 let decrypted_key_slice = cbc::Decryptor::<aes::Aes256>::new(key, iv.into())
34 .decrypt_padded::<Pkcs7>(&mut data)
35 .map_err(|_| DecryptError {})?;
36
37 let decrypted_len = decrypted_key_slice.len();
40 data.truncate(decrypted_len);
41
42 Ok(data)
43}
44
45pub(crate) fn decrypt_aes256_hmac(
49 iv: &[u8; 16],
50 mac: &[u8; 32],
51 data: Vec<u8>,
52 mac_key: &Array<u8, U32>,
53 key: &Array<u8, U32>,
54) -> Result<Vec<u8>, DecryptError> {
55 let res = generate_mac(mac_key, iv, &data);
56 if res.ct_ne(mac).into() {
57 return Err(DecryptError {});
58 }
59 decrypt_aes256(iv, data, key)
60}
61
62pub(crate) fn encrypt_aes256_hmac(
68 data_dec: &[u8],
69 mac_key: &Array<u8, U32>,
70 key: &Array<u8, U32>,
71) -> Result<([u8; 16], [u8; 32], Vec<u8>)> {
72 let rng = rand::rng();
73 let (iv, data) = encrypt_aes256_internal(rng, data_dec, key);
74 let mac = generate_mac(mac_key, &iv, &data);
75
76 Ok((iv, mac, data))
77}
78
79fn encrypt_aes256_internal(
84 mut rng: impl rand::Rng,
85 data_dec: &[u8],
86 key: &Array<u8, U32>,
87) -> ([u8; 16], Vec<u8>) {
88 let mut iv = [0u8; 16];
89 rng.fill_bytes(&mut iv);
90 let data =
91 cbc::Encryptor::<aes::Aes256>::new(key, &iv.into()).encrypt_padded_vec::<Pkcs7>(data_dec);
92
93 (iv, data)
94}
95
96fn generate_mac(mac_key: &[u8], iv: &[u8], data: &[u8]) -> [u8; 32] {
98 let mut hmac =
99 PbkdfSha256Hmac::new_from_slice(mac_key).expect("hmac new_from_slice should not fail");
100 hmac.update(iv);
101 hmac.update(data);
102 let mac: [u8; PBKDF_SHA256_HMAC_OUT_SIZE] = (*hmac.finalize().into_bytes())
103 .try_into()
104 .expect("HMAC output size to be correct");
106 mac
107}
108
109#[cfg(test)]
110mod tests {
111 use bitwarden_encoding::B64;
112 use hybrid_array::ArraySize;
113 use rand::SeedableRng;
114
115 use super::*;
116
117 fn generate_array<N: ArraySize>(offset: u8, increment: u8) -> Array<u8, N> {
120 Array::from_fn(|i| offset + i as u8 * increment)
121 }
122
123 fn generate_vec(length: usize, offset: u8, increment: u8) -> Vec<u8> {
126 (0..length).map(|i| offset + i as u8 * increment).collect()
127 }
128
129 #[test]
130 fn test_encrypt_aes256_internal() {
131 let key = generate_array(0, 1);
132
133 let rng = rand_chacha::ChaCha8Rng::from_seed([0u8; 32]);
134 let result = encrypt_aes256_internal(rng, "EncryptMe!".as_bytes(), &key);
135 assert_eq!(
136 result,
137 (
138 [
139 62, 0, 239, 47, 137, 95, 64, 214, 127, 91, 184, 232, 31, 9, 165, 161
140 ],
141 vec![
142 214, 76, 187, 97, 58, 146, 212, 140, 95, 164, 177, 204, 179, 133, 172, 148
143 ]
144 )
145 );
146 }
147
148 #[test]
149 fn test_generate_mac() {
150 let mac_key = generate_vec(16, 0, 16);
151
152 let iv = generate_vec(16, 0, 16);
153 let data = generate_vec(16, 0, 16);
154
155 let mac = generate_mac(&mac_key, &iv, &data);
156 assert!(mac.iter().any(|&b| b != 0));
157 }
158
159 #[test]
160 fn test_decrypt_aes256() {
161 let iv = generate_vec(16, 0, 1);
162 let iv: &[u8; 16] = iv.as_slice().try_into().unwrap();
163 let key = generate_array(0, 1);
164 let data: B64 = ("ByUF8vhyX4ddU9gcooznwA==").parse().unwrap();
165
166 let decrypted = decrypt_aes256(iv, data.into(), &key).unwrap();
167
168 assert_eq!(String::from_utf8(decrypted).unwrap(), "EncryptMe!");
169 }
170}