bitwarden_crypto/hazmat/symmetric_encryption/
aes_gcm.rs1use aes::cipher::common::Generate;
20use aes_gcm::{AeadCore, AeadInOut, Aes256Gcm as Aes256GcmAlg, KeyInit, aead::Nonce};
21use coset::{CoseEncrypt, CoseEncrypt0};
22use typenum::Unsigned;
23
24use super::Aead;
25use crate::CryptoError;
26
27pub(crate) const NONCE_SIZE: usize = <Aes256GcmAlg as AeadCore>::NonceSize::USIZE;
28pub(crate) const KEY_SIZE: usize = 32;
29
30pub(crate) struct Aes256Gcm;
35
36impl Aead for Aes256Gcm {
37 type Key = [u8; KEY_SIZE];
38 type Ciphertext = Aes256GcmCiphertext;
39 type Nonce = Aes256GcmNonce;
40
41 fn encrypt(
42 key: &Self::Key,
43 nonce: &Self::Nonce,
44 plaintext: &[u8],
45 associated_data: &[u8],
46 ) -> Self::Ciphertext {
47 let mut buffer = plaintext.to_vec();
49 Aes256GcmAlg::new(key.into())
50 .encrypt_in_place(&nonce.0, associated_data, &mut buffer)
51 .expect("encryption failed");
52
53 Aes256GcmCiphertext {
54 encrypted_bytes: buffer,
55 }
56 }
57
58 fn decrypt(
59 key: &Self::Key,
60 nonce: &Self::Nonce,
61 ciphertext: &Self::Ciphertext,
62 associated_data: &[u8],
63 ) -> Result<Vec<u8>, CryptoError> {
64 let mut buffer = ciphertext.encrypted_bytes().to_vec();
65 Aes256GcmAlg::new(key.into())
66 .decrypt_in_place(&nonce.0, associated_data, &mut buffer)
67 .map_err(|_| CryptoError::KeyDecrypt)?;
68 Ok(buffer)
69 }
70}
71
72pub(crate) struct Aes256GcmNonce(Nonce<Aes256GcmAlg>);
78
79impl Aes256GcmNonce {
80 pub(crate) fn make() -> Self {
82 let mut rng = rand::rng();
83 Aes256GcmNonce(Nonce::<Aes256GcmAlg>::generate_from_rng(&mut rng))
84 }
85
86 pub(crate) fn as_bytes(&self) -> &[u8] {
88 self.0.as_slice()
89 }
90
91 fn from_cose_iv(iv: &[u8]) -> Result<Self, CryptoError> {
93 let nonce: [u8; NONCE_SIZE] = iv.try_into().map_err(|_| CryptoError::InvalidNonceLength)?;
94 Ok(Aes256GcmNonce(nonce.into()))
95 }
96}
97
98impl TryFrom<&CoseEncrypt> for Aes256GcmNonce {
100 type Error = CryptoError;
101
102 fn try_from(cose_encrypt: &CoseEncrypt) -> Result<Self, Self::Error> {
103 Self::from_cose_iv(cose_encrypt.unprotected.iv.as_slice())
104 }
105}
106
107impl TryFrom<&CoseEncrypt0> for Aes256GcmNonce {
109 type Error = CryptoError;
110
111 fn try_from(cose_encrypt0: &CoseEncrypt0) -> Result<Self, Self::Error> {
112 Self::from_cose_iv(cose_encrypt0.unprotected.iv.as_slice())
113 }
114}
115
116pub(crate) struct Aes256GcmCiphertext {
117 encrypted_bytes: Vec<u8>,
118}
119
120impl Aes256GcmCiphertext {
121 pub(crate) fn encrypted_bytes(&self) -> &[u8] {
122 &self.encrypted_bytes
123 }
124}
125
126impl From<Vec<u8>> for Aes256GcmCiphertext {
129 fn from(encrypted_bytes: Vec<u8>) -> Self {
130 Aes256GcmCiphertext { encrypted_bytes }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 #[cfg(test)]
137 use super::*;
138
139 #[test]
140 fn test_encrypt_decrypt_aes256_gcm() {
141 let key = [0u8; KEY_SIZE];
142 let nonce = Aes256GcmNonce::make();
143 let plaintext_secret_data = b"My secret data";
144 let authenticated_data = b"My authenticated data";
145 let encrypted = Aes256Gcm::encrypt(&key, &nonce, plaintext_secret_data, authenticated_data);
146 let decrypted = Aes256Gcm::decrypt(&key, &nonce, &encrypted, authenticated_data).unwrap();
147 assert_eq!(plaintext_secret_data, decrypted.as_slice());
148 }
149
150 #[test]
151 fn test_make_nonce_has_correct_length() {
152 let nonce = Aes256GcmNonce::make();
153 assert_eq!(nonce.as_bytes().len(), NONCE_SIZE);
154 }
155
156 #[test]
157 fn test_fails_when_ciphertext_changed() {
158 let key = [0u8; KEY_SIZE];
159 let nonce = Aes256GcmNonce::make();
160 let plaintext_secret_data = b"My secret data";
161 let authenticated_data = b"My authenticated data";
162
163 let mut encrypted =
164 Aes256Gcm::encrypt(&key, &nonce, plaintext_secret_data, authenticated_data);
165 encrypted.encrypted_bytes[0] = encrypted.encrypted_bytes[0].wrapping_add(1);
166 let result = Aes256Gcm::decrypt(&key, &nonce, &encrypted, authenticated_data);
167 assert!(result.is_err());
168 }
169
170 #[test]
171 fn test_fails_when_associated_data_changed() {
172 let key = [0u8; KEY_SIZE];
173 let nonce = Aes256GcmNonce::make();
174 let plaintext_secret_data = b"My secret data";
175 let mut authenticated_data = b"My authenticated data".to_vec();
176
177 let encrypted = Aes256Gcm::encrypt(
178 &key,
179 &nonce,
180 plaintext_secret_data,
181 authenticated_data.as_slice(),
182 );
183 authenticated_data[0] = authenticated_data[0].wrapping_add(1);
184 let result = Aes256Gcm::decrypt(&key, &nonce, &encrypted, authenticated_data.as_slice());
185 assert!(result.is_err());
186 }
187
188 #[test]
189 fn test_fails_when_nonce_changed() {
190 let key = [0u8; KEY_SIZE];
191 let nonce = Aes256GcmNonce::make();
192 let plaintext_secret_data = b"My secret data";
193 let authenticated_data = b"My authenticated data";
194
195 let encrypted = Aes256Gcm::encrypt(&key, &nonce, plaintext_secret_data, authenticated_data);
196 let other_nonce = Aes256GcmNonce::make();
198 let result = Aes256Gcm::decrypt(&key, &other_nonce, &encrypted, authenticated_data);
199 assert!(result.is_err());
200 }
201}