1 /* Copyright (c) 2023, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16 use crate::{CSlice, CSliceMut};
17 use alloc::vec::Vec;
18 use bssl_sys::{EVP_AEAD, EVP_AEAD_CTX};
19
20 /// Error returned in the event of an unsuccessful AEAD operation.
21 #[derive(Debug)]
22 pub struct AeadError;
23
24 /// Authenticated Encryption with Associated Data (AEAD) algorithm trait.
25 pub trait Aead {
26 /// The size of the auth tag for the given AEAD implementation. This is the amount of bytes
27 /// appended to the data when it is encrypted.
28 const TAG_SIZE: usize;
29
30 /// The byte array nonce type which specifies the size of the nonce used in the aes operations.
31 type Nonce: AsRef<[u8]>;
32
33 /// Encrypt the given buffer containing a plaintext message. On success returns the encrypted
34 /// `msg` and appended auth tag, which will result in a Vec which is `Self::TAG_SIZE` bytes
35 /// greater than the initial message.
encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>36 fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
37
38 /// Decrypt the message, returning the decrypted plaintext or an error in the event the
39 /// provided authentication tag does not match the given ciphertext. On success the returned
40 /// Vec will only contain the plaintext and so will be `Self::TAG_SIZE` bytes less than the
41 /// initial message.
decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>42 fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &Self::Nonce) -> Result<Vec<u8>, AeadError>;
43 }
44
45 /// AES-GCM-SIV implementation.
46 pub struct AesGcmSiv(AeadImpl<12, 16>);
47
48 /// Instantiates a new AES-128-GCM-SIV instance from key material.
new_aes_128_gcm_siv(key: &[u8; 16]) -> AesGcmSiv49 pub fn new_aes_128_gcm_siv(key: &[u8; 16]) -> AesGcmSiv {
50 AesGcmSiv(AeadImpl::new::<EvpAes128GcmSiv>(key))
51 }
52
53 /// Instantiates a new AES-256-GCM-SIV instance from key material.
new_aes_256_gcm_siv(key: &[u8; 32]) -> AesGcmSiv54 pub fn new_aes_256_gcm_siv(key: &[u8; 32]) -> AesGcmSiv {
55 AesGcmSiv(AeadImpl::new::<EvpAes256GcmSiv>(key))
56 }
57
58 impl Aead for AesGcmSiv {
59 const TAG_SIZE: usize = 16;
60 type Nonce = [u8; 12];
61
encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError>62 fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
63 self.0.encrypt(msg, aad, nonce)
64 }
65
decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError>66 fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
67 self.0.decrypt(msg, aad, nonce)
68 }
69 }
70
71 trait EvpAeadType {
72 type Key: AsRef<[u8]>;
evp_aead() -> *const EVP_AEAD73 fn evp_aead() -> *const EVP_AEAD;
74 }
75
76 struct EvpAes128GcmSiv;
77 impl EvpAeadType for EvpAes128GcmSiv {
78 type Key = [u8; 16];
79
evp_aead() -> *const EVP_AEAD80 fn evp_aead() -> *const EVP_AEAD {
81 // Safety:
82 // - this just returns a constant value
83 unsafe { bssl_sys::EVP_aead_aes_128_gcm_siv() }
84 }
85 }
86
87 struct EvpAes256GcmSiv;
88 impl EvpAeadType for EvpAes256GcmSiv {
89 type Key = [u8; 32];
90
evp_aead() -> *const EVP_AEAD91 fn evp_aead() -> *const EVP_AEAD {
92 // Safety:
93 // - this just returns a constant value
94 unsafe { bssl_sys::EVP_aead_aes_256_gcm_siv() }
95 }
96 }
97
98 /// AES-GCM implementation.
99 pub struct AesGcm(AeadImpl<12, 16>);
100
101 /// Instantiates a new AES-128-GCM instance from key material.
new_aes_128_gcm(key: &[u8; 16]) -> AesGcm102 pub fn new_aes_128_gcm(key: &[u8; 16]) -> AesGcm {
103 AesGcm(AeadImpl::new::<EvpAes128Gcm>(key))
104 }
105
106 /// Instantiates a new AES-256-GCM instance from key material.
new_aes_256_gcm(key: &[u8; 32]) -> AesGcm107 pub fn new_aes_256_gcm(key: &[u8; 32]) -> AesGcm {
108 AesGcm(AeadImpl::new::<EvpAes256Gcm>(key))
109 }
110
111 impl Aead for AesGcm {
112 const TAG_SIZE: usize = 16;
113 type Nonce = [u8; 12];
114
encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError>115 fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
116 self.0.encrypt(msg, aad, nonce)
117 }
118
decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError>119 fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; 12]) -> Result<Vec<u8>, AeadError> {
120 self.0.decrypt(msg, aad, nonce)
121 }
122 }
123
124 struct EvpAes128Gcm;
125 impl EvpAeadType for EvpAes128Gcm {
126 type Key = [u8; 16];
127
evp_aead() -> *const EVP_AEAD128 fn evp_aead() -> *const EVP_AEAD {
129 // Safety:
130 // - this just returns a constant value
131 unsafe { bssl_sys::EVP_aead_aes_128_gcm() }
132 }
133 }
134
135 struct EvpAes256Gcm;
136 impl EvpAeadType for EvpAes256Gcm {
137 type Key = [u8; 32];
138
evp_aead() -> *const EVP_AEAD139 fn evp_aead() -> *const EVP_AEAD {
140 // Safety:
141 // - this just returns a constant value
142 unsafe { bssl_sys::EVP_aead_aes_256_gcm() }
143 }
144 }
145
146 // Private implementation of an AEAD which is generic over Nonce size and Tag size. This should
147 // only be exposed publicly by wrapper types which provide the correctly sized const generics for
148 // the given aead algorithm.
149 struct AeadImpl<const N: usize, const T: usize>(*mut EVP_AEAD_CTX);
150
151 impl<const N: usize, const T: usize> AeadImpl<N, T> {
152 // Create a new AeadImpl instance from key material and for a supported AeadType.
new<A: EvpAeadType>(key: &A::Key) -> Self153 fn new<A: EvpAeadType>(key: &A::Key) -> Self {
154 let key_cslice = CSlice::from(key.as_ref());
155
156 // Safety:
157 // - This is always safe as long as the correct key size is set by the wrapper type.
158 let ctx = unsafe {
159 bssl_sys::EVP_AEAD_CTX_new(
160 A::evp_aead(),
161 key_cslice.as_ptr(),
162 key_cslice.len(),
163 bssl_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as usize,
164 )
165 };
166 assert!(!ctx.is_null());
167 AeadImpl(ctx)
168 }
169
170 // Encrypts msg in-place, adding enough space to msg for the auth tag.
encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; N]) -> Result<Vec<u8>, AeadError>171 fn encrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; N]) -> Result<Vec<u8>, AeadError> {
172 let mut out = Vec::new();
173 out.resize(msg.len() + T, 0u8);
174
175 let mut out_cslice = CSliceMut::from(out.as_mut_slice());
176 let msg_cslice = CSlice::from(msg);
177 let aad_cslice = CSlice::from(aad);
178 let nonce_cslice = CSlice::from(nonce.as_slice());
179 let mut out_len = 0usize;
180
181 // Safety:
182 // - The buffers are all valid, with corresponding ptr and length
183 let result = unsafe {
184 bssl_sys::EVP_AEAD_CTX_seal(
185 self.0,
186 out_cslice.as_mut_ptr(),
187 &mut out_len,
188 out_cslice.len(),
189 nonce_cslice.as_ptr(),
190 nonce_cslice.len(),
191 msg_cslice.as_ptr(),
192 msg_cslice.len(),
193 aad_cslice.as_ptr(),
194 aad_cslice.len(),
195 )
196 };
197
198 if result == 1 {
199 // Verify the correct number of bytes were written.
200 assert_eq!(out_len, out.len());
201 Ok(out)
202 } else {
203 Err(AeadError)
204 }
205 }
206
207 // Decrypts msg in-place, on success msg will contain the plain text alone, without the auth
208 // tag.
decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; N]) -> Result<Vec<u8>, AeadError>209 fn decrypt(&self, msg: &[u8], aad: &[u8], nonce: &[u8; N]) -> Result<Vec<u8>, AeadError> {
210 if msg.len() < T {
211 return Err(AeadError);
212 }
213 let mut out = Vec::new();
214 out.resize(msg.len() - T, 0u8);
215
216 let mut out_cslice = CSliceMut::from(out.as_mut_slice());
217 let aad_cslice = CSlice::from(aad);
218 let msg_cslice = CSlice::from(msg);
219 let mut out_len = 0usize;
220
221 // Safety:
222 // - The buffers are all valid, with corresponding ptr and length
223 let result = unsafe {
224 bssl_sys::EVP_AEAD_CTX_open(
225 self.0,
226 out_cslice.as_mut_ptr(),
227 &mut out_len,
228 out_cslice.len(),
229 nonce.as_ptr(),
230 nonce.len(),
231 msg_cslice.as_ptr(),
232 msg_cslice.len(),
233 aad_cslice.as_ptr(),
234 aad_cslice.len(),
235 )
236 };
237
238 if result == 1 {
239 // Verify the correct number of bytes were written.
240 assert_eq!(out_len, out.len());
241 Ok(out)
242 } else {
243 Err(AeadError)
244 }
245 }
246 }
247
248 impl<const N: usize, const T: usize> Drop for AeadImpl<N, T> {
drop(&mut self)249 fn drop(&mut self) {
250 // Safety:
251 // - `self.0` was allocated by `EVP_AEAD_CTX_new` and has not yet been freed.
252 unsafe { bssl_sys::EVP_AEAD_CTX_free(self.0) }
253 }
254 }
255
256 #[cfg(test)]
257 mod test {
258 use super::*;
259 use crate::test_helpers::decode_hex;
260
261 #[test]
aes_128_gcm_siv_tests()262 fn aes_128_gcm_siv_tests() {
263 // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
264 // TC1 - Empty Message
265 let key = decode_hex("01000000000000000000000000000000");
266 let nonce = decode_hex("030000000000000000000000");
267 let tag: [u8; 16] = decode_hex("dc20e2d83f25705bb49e439eca56de25");
268 let mut buf = Vec::from(&[] as &[u8]);
269 let aes = new_aes_128_gcm_siv(&key);
270 let result = aes.encrypt(&mut buf, b"", &nonce);
271 assert!(result.is_ok());
272 assert_eq!(result.unwrap(), &tag);
273
274 // TC2
275 let msg: [u8; 8] = decode_hex("0100000000000000");
276 let ct: [u8; 8] = decode_hex("b5d839330ac7b786");
277 let tag: [u8; 16] = decode_hex("578782fff6013b815b287c22493a364c");
278 let result = aes.encrypt(&msg, b"", &nonce);
279 assert!(result.is_ok());
280 let mut result_vec = result.unwrap();
281 assert_eq!(&result_vec[..8], &ct);
282 assert_eq!(&result_vec[8..], &tag);
283 let result = aes.decrypt(result_vec.as_mut_slice(), b"", &nonce);
284 assert!(result.is_ok());
285 assert_eq!(&result.unwrap(), &msg);
286
287 // TC14 contains associated data
288 let msg: [u8; 4] = decode_hex("02000000");
289 let ct: [u8; 4] = decode_hex("a8fe3e87");
290 let aad: [u8; 12] = decode_hex("010000000000000000000000");
291 let tag: [u8; 16] = decode_hex("07eb1f84fb28f8cb73de8e99e2f48a14");
292 let result = aes.encrypt(&msg, &aad, &nonce);
293 assert!(result.is_ok());
294 let mut result_vec = result.unwrap();
295 assert_eq!(&result_vec[..4], &ct);
296 assert_eq!(&result_vec[4..], &tag);
297 let result = aes.decrypt(result_vec.as_mut_slice(), &aad, &nonce);
298 assert!(result.is_ok());
299 assert_eq!(&result.unwrap(), &msg);
300 }
301
302 #[test]
aes_256_gcm_siv_tests()303 fn aes_256_gcm_siv_tests() {
304 // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json
305 // TC77
306 let test_key =
307 decode_hex("0100000000000000000000000000000000000000000000000000000000000000");
308 let nonce = decode_hex("030000000000000000000000");
309 let aes = new_aes_256_gcm_siv(&test_key);
310 let mut msg: [u8; 8] = decode_hex("0100000000000000");
311 let ct: [u8; 8] = decode_hex("c2ef328e5c71c83b");
312 let tag: [u8; 16] = decode_hex("843122130f7364b761e0b97427e3df28");
313 let enc_result = aes.encrypt(&mut msg, b"", &nonce);
314 assert!(enc_result.is_ok());
315 let mut enc_data = enc_result.unwrap();
316 assert_eq!(&enc_data[..8], &ct);
317 assert_eq!(&enc_data[8..], &tag);
318 let result = aes.decrypt(enc_data.as_mut_slice(), b"", &nonce);
319 assert!(result.is_ok());
320 assert_eq!(&result.unwrap(), &msg);
321
322 // TC78
323 let mut msg: [u8; 12] = decode_hex("010000000000000000000000");
324 let ct: [u8; 12] = decode_hex("9aab2aeb3faa0a34aea8e2b1");
325 let tag: [u8; 16] = decode_hex("8ca50da9ae6559e48fd10f6e5c9ca17e");
326 let enc_result = aes.encrypt(&mut msg, b"", &nonce);
327 assert!(enc_result.is_ok());
328 let mut enc_data = enc_result.unwrap();
329 assert_eq!(&enc_data[..12], &ct);
330 assert_eq!(&enc_data[12..], &tag);
331 let result = aes.decrypt(enc_data.as_mut_slice(), b"", &nonce);
332 assert!(result.is_ok());
333 assert_eq!(&result.unwrap(), &msg);
334
335 // TC89 contains associated data
336 let mut msg: [u8; 4] = decode_hex("02000000");
337 let ct: [u8; 4] = decode_hex("22b3f4cd");
338 let tag: [u8; 16] = decode_hex("1835e517741dfddccfa07fa4661b74cf");
339 let aad: [u8; 12] = decode_hex("010000000000000000000000");
340 let enc_result = aes.encrypt(&mut msg, &aad, &nonce);
341 assert!(enc_result.is_ok());
342 let mut enc_data = enc_result.unwrap();
343 assert_eq!(&enc_data[..4], &ct);
344 assert_eq!(&enc_data[4..], &tag);
345 let result = aes.decrypt(enc_data.as_mut_slice(), &aad, &nonce);
346 assert!(result.is_ok());
347 assert_eq!(&result.unwrap(), &msg);
348 }
349
350 #[test]
aes_128_gcm_tests()351 fn aes_128_gcm_tests() {
352 // TC 1 from crypto/cipher_extra/test/aes_128_gcm_tests.txt
353 let key = decode_hex("d480429666d48b400633921c5407d1d1");
354 let nonce = decode_hex("3388c676dc754acfa66e172a");
355 let tag: [u8; 16] = decode_hex("7d7daf44850921a34e636b01adeb104f");
356 let mut buf = Vec::from(&[] as &[u8]);
357 let aes = new_aes_128_gcm(&key);
358 let result = aes.encrypt(&mut buf, b"", &nonce);
359 assert!(result.is_ok());
360 assert_eq!(result.unwrap(), &tag);
361
362 // TC2
363 let key = decode_hex("3881e7be1bb3bbcaff20bdb78e5d1b67");
364 let nonce = decode_hex("dcf5b7ae2d7552e2297fcfa9");
365 let msg: [u8; 5] = decode_hex("0a2714aa7d");
366 let ad: [u8; 5] = decode_hex("c60c64bbf7");
367 let ct: [u8; 5] = decode_hex("5626f96ecb");
368 let tag: [u8; 16] = decode_hex("ff4c4f1d92b0abb1d0820833d9eb83c7");
369
370 let mut buf = Vec::from(msg.as_slice());
371 let aes = new_aes_128_gcm(&key);
372 let result = aes.encrypt(&mut buf, &ad, &nonce);
373 assert!(result.is_ok());
374 let mut data = result.unwrap();
375 assert_eq!(&data[..5], &ct);
376 assert_eq!(&data[5..], &tag);
377 let result = aes.decrypt(data.as_mut_slice(), &ad, &nonce);
378 assert!(result.is_ok());
379 assert_eq!(result.unwrap(), &msg);
380 }
381
382 #[test]
aes_256_gcm_tests()383 fn aes_256_gcm_tests() {
384 // TC 1 from crypto/cipher_extra/test/aes_256_gcm_tests.txt
385 let key = decode_hex("e5ac4a32c67e425ac4b143c83c6f161312a97d88d634afdf9f4da5bd35223f01");
386 let nonce = decode_hex("5bf11a0951f0bfc7ea5c9e58");
387 let tag: [u8; 16] = decode_hex("d7cba289d6d19a5af45dc13857016bac");
388 let mut buf = Vec::from(&[] as &[u8]);
389 let aes = new_aes_256_gcm(&key);
390 let result = aes.encrypt(&mut buf, b"", &nonce);
391 assert!(result.is_ok());
392 assert_eq!(result.unwrap(), &tag);
393
394 // TC2
395 let key = decode_hex("73ad7bbbbc640c845a150f67d058b279849370cd2c1f3c67c4dd6c869213e13a");
396 let nonce = decode_hex("a330a184fc245812f4820caa");
397 let msg: [u8; 5] = decode_hex("f0535fe211");
398 let ad: [u8; 5] = decode_hex("e91428be04");
399 let ct: [u8; 5] = decode_hex("e9b8a896da");
400 let tag: [u8; 16] = decode_hex("9115ed79f26a030c14947b3e454db9e7");
401
402 let mut buf = Vec::from(msg.as_slice());
403 let aes = new_aes_256_gcm(&key);
404 let result = aes.encrypt(&mut buf, &ad, &nonce);
405 assert!(result.is_ok());
406 let mut data = result.unwrap();
407 assert_eq!(&data[..5], &ct);
408 assert_eq!(&data[5..], &tag);
409 let result = aes.decrypt(data.as_mut_slice(), &ad, &nonce);
410 assert!(result.is_ok());
411 assert_eq!(result.unwrap(), &msg);
412 }
413
414 #[test]
test_invalid_data_length_decrypt()415 fn test_invalid_data_length_decrypt() {
416 let key = decode_hex("00000000000000000000000000000000");
417 let nonce = decode_hex("000000000000000000000000");
418 let buf = Vec::from(&[] as &[u8]);
419 let aes = new_aes_128_gcm_siv(&key);
420 let result = aes.decrypt(&buf, b"", &nonce);
421 assert!(result.is_err());
422 }
423 }
424