• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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