1use constant_time_eq::constant_time_eq;
2
3use super::{
4 aes::{GCM_MAX_LEN, encrypt_block, expand_key},
5 ghash::{GHashPowers, compute_tag, precompute_ghash_powers},
6};
7use crate::{
8 Aead, AeadError, Hash,
9 aes::{RoundKeys, aes::RoundKeysSoftware},
10};
11
12#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
18pub struct Aes128Gcm(pub(crate) AesGcm<11>);
19
20impl Aes128Gcm {
21 pub const KEY_SIZE: usize = 16;
22
23 #[inline]
29 pub fn new(key: &[u8; Self::KEY_SIZE]) -> Self {
30 Self(AesGcm::<11>::new(key))
31 }
32}
33
34impl Aead for Aes128Gcm {
35 const KEY_SIZE: usize = 16;
36 const TAG_SIZE: usize = 16;
37 const NONCE_SIZE: usize = 12;
38
39 #[inline]
40 fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Hash {
41 let nonce_arr: &[u8; 12] = nonce.try_into().map_err(|_| AeadError::InvalidNonce).unwrap();
42
43 self.0.encrypt_in_place(in_out, nonce_arr, aad)
44 }
45
46 #[inline]
47 fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError> {
48 let nonce_arr: &[u8; 12] = nonce.try_into().map_err(|_| AeadError::InvalidNonce)?;
49 let tag_arr: &[u8; 16] = tag.try_into().map_err(|_| AeadError::InvalidCiphertext)?;
50
51 self.0.decrypt_in_place(in_out, nonce_arr, aad, tag_arr)
52 }
53}
54
55#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
61pub struct Aes256Gcm(pub(crate) AesGcm<15>);
62
63impl Aes256Gcm {
64 pub const KEY_SIZE: usize = 32;
65
66 #[inline]
72 pub fn new(key: &[u8; Self::KEY_SIZE]) -> Self {
73 Self(AesGcm::<15>::new(key))
74 }
75}
76
77impl Aead for Aes256Gcm {
78 const KEY_SIZE: usize = 32;
79 const TAG_SIZE: usize = 16;
80 const NONCE_SIZE: usize = 12;
81
82 #[inline]
83 fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Hash {
84 let nonce_arr: &[u8; 12] = nonce.try_into().map_err(|_| AeadError::InvalidNonce).unwrap();
85
86 self.0.encrypt_in_place(in_out, nonce_arr, aad)
87 }
88
89 #[inline]
90 fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError> {
91 let nonce_arr: &[u8; 12] = nonce.try_into().map_err(|_| AeadError::InvalidNonce)?;
92 let tag_arr: &[u8; 16] = tag.try_into().map_err(|_| AeadError::InvalidCiphertext)?;
93
94 self.0.decrypt_in_place(in_out, nonce_arr, aad, tag_arr)
95 }
96}
97
98#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
113pub(crate) struct AesGcm<const N: usize> {
114 pub(crate) round_keys: RoundKeys<N>,
115 pub(crate) h_powers: GHashPowers,
116}
117
118impl AesGcm<11> {
119 pub const KEY_SIZE: usize = 16;
120
121 pub fn new(key: &[u8; Self::KEY_SIZE]) -> Self {
122 Self::new_inner(key)
123 }
124}
125
126impl AesGcm<15> {
127 pub const KEY_SIZE: usize = 32;
128
129 pub fn new(key: &[u8; Self::KEY_SIZE]) -> Self {
130 Self::new_inner(key)
131 }
132}
133
134impl<const N: usize> AesGcm<N> {
135 fn new_inner(key: &[u8]) -> Self {
136 const { assert!(N == 11 || N == 15) };
137
138 let round_keys_software = expand_key(key);
139
140 #[cfg(target_arch = "aarch64")]
141 {
142 use core::arch::aarch64::*;
143
144 let (h_powers_bytes, _h) = precompute_ghash_powers::<N>(key);
145 let mut h_powers = [unsafe { vdupq_n_u8(0) }; 8];
146 for i in 0..8 {
147 h_powers[i] = unsafe { vld1q_u8(h_powers_bytes[i].as_ptr()) };
148 }
149 let h_powers = GHashPowers::Armv8(h_powers);
150
151 #[cfg(feature = "std")]
152 if std::arch::is_aarch64_feature_detected!("aes") {
153 return AesGcm {
154 round_keys: RoundKeys::Armv8(super::aes_arm64::expand_key_armv8(round_keys_software)),
155 h_powers,
156 };
157 }
158
159 #[cfg(all(not(feature = "std"), target_feature = "aes"))]
160 return AesGcm {
161 round_keys: RoundKeys::Armv8(super::aes_arm64::expand_key_armv8(round_keys_software)),
162 h_powers,
163 };
164 }
165
166 #[cfg(target_arch = "x86_64")]
167 {
168 use core::arch::x86_64::*;
169
170 let (h_powers_bytes, _h) = precompute_ghash_powers::<N>(key);
171 let mut h_powers = unsafe { [_mm_setzero_si128(); 8] };
172 for i in 0..8 {
173 h_powers[i] = unsafe { _mm_loadu_si128(h_powers_bytes[i].as_ptr().cast()) };
174 }
175
176 #[cfg(feature = "std")]
177 if std::arch::is_x86_feature_detected!("aes")
178 && std::arch::is_x86_feature_detected!("pclmulqdq")
179 && std::arch::is_x86_feature_detected!("ssse3")
180 && std::arch::is_x86_feature_detected!("sse4.1")
181 {
182 return AesGcm {
183 round_keys: RoundKeys::X86_64(super::aes_amd64::expand_key_x86_64(round_keys_software)),
184 h_powers: GHashPowers::X86_64(h_powers),
185 };
186 }
187
188 #[cfg(all(
189 not(feature = "std"),
190 target_feature = "aes",
191 target_feature = "pclmulqdq",
192 target_feature = "ssse3",
193 target_feature = "sse4.1"
194 ))]
195 return AesGcm {
196 round_keys: RoundKeys::X86_64(super::super::aes_amd64::expand_key_x86_64(round_keys_software)),
197 h_powers: GHashPowers::X86_64(h_powers),
198 };
199 }
200
201 AesGcm {
202 round_keys: RoundKeys::Software(round_keys_software),
203 h_powers: GHashPowers::Software(encrypt_block(&round_keys_software, &[0u8; 16])),
204 }
205 }
206
207 fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8; 12], aad: &[u8]) -> Hash {
208 assert!(
209 in_out.len() as u64 <= GCM_MAX_LEN,
210 "GCM plaintext exceeds maximum allowed length (2^32 - 2 blocks)"
211 );
212
213 match (&self.round_keys, &self.h_powers) {
214 #[cfg(target_arch = "aarch64")]
215 (RoundKeys::Armv8(round_keys), GHashPowers::Armv8(h_powers)) => unsafe {
216 use crate::aes::aes_gcm_arm64::gcm_encrypt_armv8;
217 gcm_encrypt_armv8(round_keys, h_powers, in_out, nonce, aad)
218 },
219 #[cfg(target_arch = "x86_64")]
220 (RoundKeys::X86_64(round_keys), GHashPowers::X86_64(h_powers)) => unsafe {
221 use crate::aes::aes_gcm_amd64::gcm_encrypt_aesni;
222 gcm_encrypt_aesni(round_keys, h_powers, in_out, nonce, aad)
223 },
224 (RoundKeys::Software(round_keys), GHashPowers::Software(h)) => {
225 self.encrypt_in_place_soft(in_out, round_keys, h, nonce, aad)
226 }
227 _ => unreachable!(),
228 }
229 }
230
231 fn decrypt_in_place(
232 &self,
233 in_out: &mut [u8],
234 nonce: &[u8; 12],
235 aad: &[u8],
236 tag: &[u8; 16],
237 ) -> Result<(), AeadError> {
238 if in_out.len() as u64 > GCM_MAX_LEN {
239 return Err(AeadError::InvalidCiphertext);
240 }
241
242 match (&self.round_keys, &self.h_powers) {
243 #[cfg(target_arch = "aarch64")]
244 (RoundKeys::Armv8(round_keys), GHashPowers::Armv8(h_powers)) => unsafe {
245 use crate::aes::aes_gcm_arm64::gcm_decrypt_armv8;
246 gcm_decrypt_armv8(round_keys, h_powers, in_out, tag, nonce, aad)
247 },
248 #[cfg(target_arch = "x86_64")]
249 (RoundKeys::X86_64(round_keys), GHashPowers::X86_64(h_powers)) => unsafe {
250 use crate::aes::aes_gcm_amd64::gcm_decrypt_aesni;
251 gcm_decrypt_aesni(round_keys, h_powers, in_out, tag, nonce, aad)
252 },
253 (RoundKeys::Software(round_keys), GHashPowers::Software(h)) => {
254 self.decrypt_in_place_soft(in_out, round_keys, h, tag, nonce, aad)
255 }
256 _ => unreachable!(),
257 }
258 }
259
260 pub(crate) fn encrypt_in_place_soft(
262 &self,
263 in_out: &mut [u8],
264 round_keys: &RoundKeysSoftware<N>,
265 h: &[u8; 16],
266 nonce: &[u8; 12],
267 aad: &[u8],
268 ) -> Hash {
269 let mut j0 = [0u8; 16];
270 j0[..12].copy_from_slice(nonce);
271 j0[15] = 1;
272
273 let ej0 = encrypt_block(round_keys, &j0);
274
275 j0[15] = 2;
276 super::aes_ct::xor_keystream_soft(round_keys, &mut j0, in_out);
277 compute_tag(h, aad, in_out, &ej0)
278 }
279
280 pub(crate) fn decrypt_in_place_soft(
282 &self,
283 in_out: &mut [u8],
284 round_keys: &RoundKeysSoftware<N>,
285 h: &[u8; 16],
286 tag: &[u8; 16],
287 nonce: &[u8; 12],
288 aad: &[u8],
289 ) -> Result<(), AeadError> {
290 let mut j0 = [0u8; 16];
291 j0[..12].copy_from_slice(nonce);
292 j0[15] = 1;
293
294 let ej0 = encrypt_block(round_keys, &j0);
295
296 let expected_tag = compute_tag(h, aad, in_out, &ej0);
297
298 if !constant_time_eq(tag, &expected_tag) {
299 return Err(AeadError::InvalidCiphertext);
300 }
301
302 j0[15] = 2;
303 super::aes_ct::xor_keystream_soft(round_keys, &mut j0, in_out);
304
305 Ok(())
306 }
307}
308
309#[cfg(test)]
310mod tests_128 {
311 use hex;
312
313 use super::*;
314 use crate::{
315 Aead,
316 aes::aes::{encrypt_block, expand_key},
317 };
318
319 include!("aes_gcm_128_vectors.rs");
320
321 #[test]
322 fn aes128_encrypt_block_vector() {
323 let key = [0u8; 16];
324 let pt = [0u8; 16];
325 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
326 let ct = encrypt_block::<11>(&rk, &pt);
327 let expected = hex::decode_array::<16>(b"66e94bd4ef8a2c3b884cfa59ca342b2e").unwrap();
328 assert_eq!(ct, expected, "AES-128 encrypt K=0, P=0 mismatch");
329 }
330
331 #[test]
332 fn aes128_fips197_vector() {
333 let key = hex::decode_array::<16>(b"2b7e151628aed2a6abf7158809cf4f3c").unwrap();
334 let pt = hex::decode_array::<16>(b"3243f6a8885a308d313198a2e0370734").unwrap();
335 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
336
337 let rk_hex: Vec<String> = rk.iter().map(|rk_i| hex::encode(rk_i)).collect();
338 assert_eq!(rk_hex[0], "2b7e151628aed2a6abf7158809cf4f3c", "rk0");
339 assert_eq!(rk_hex[1], "a0fafe1788542cb123a339392a6c7605", "rk1");
340 assert_eq!(rk_hex[2], "f2c295f27a96b9435935807a7359f67f", "rk2");
341
342 let ct = encrypt_block::<11>(&rk, &pt);
343 let ct_hex = hex::encode(ct);
344 assert_eq!(
345 ct_hex, "3925841d02dc09fbdc118597196a0b32",
346 "AES-128 FIPS 197 encrypt failed, rk3={}",
347 rk_hex[3]
348 );
349 }
350
351 fn run_gcm_vector(v: &Gcm128Vector) {
352 let key: [u8; 16] = hex::decode_array::<16>(v.key.as_bytes()).unwrap();
353 let nonce: [u8; 12] = hex::decode_array::<12>(v.nonce.as_bytes()).unwrap();
354 let pt = hex::decode(v.pt).unwrap();
355 let aad = hex::decode(v.aad).unwrap();
356 let expected_ct = hex::decode(v.ct).unwrap();
357 let expected_tag: [u8; 16] = hex::decode_array::<16>(v.tag.as_bytes()).unwrap();
358 let round_keys = expand_key::<11>(&key);
359 let h = encrypt_block::<11>(&round_keys, &[0u8; 16]);
360
361 let cipher = Aes128Gcm::new(&key);
362
363 let mut buf = pt.clone();
364 let tag = cipher.0.encrypt_in_place_soft(&mut buf, &round_keys, &h, &nonce, &aad);
365 assert_eq!(buf, expected_ct, "ciphertext mismatch for key={}", v.key);
366 assert_eq!(tag.as_ref(), &expected_tag[..], "tag mismatch for key={}", v.key);
367
368 let mut buf2 = expected_ct.clone();
369 cipher
370 .0
371 .decrypt_in_place_soft(&mut buf2, &round_keys, &h, &expected_tag, &nonce, &aad)
372 .expect("decrypt failed");
373 assert_eq!(buf2, pt, "plaintext mismatch after decrypt for key={}", v.key);
374 }
375
376 #[test]
377 fn aes128_gcm_roundtrip() {
378 let key = [0xabu8; 16];
379 let nonce = [0x01u8; 16 - 4]; let aad = b"additional data";
381 let plaintext: Vec<u8> = (0u8..=255u8).cycle().take(1024).collect();
382
383 let cipher = Aes128Gcm::new(&key);
384 let mut buf = plaintext.clone();
385 let tag = cipher.encrypt_in_place(&mut buf, &nonce, aad);
386 let tag_bytes: [u8; 16] = tag.as_ref().try_into().unwrap();
387 cipher
388 .decrypt_in_place(&mut buf, &nonce, aad, &tag_bytes)
389 .expect("decrypt failed");
390 assert_eq!(buf, plaintext);
391 }
392
393 #[test]
394 fn aes128_gcm_empty_plaintext() {
395 let key = [0x01u8; 16];
396 let nonce = [0x02u8; 12];
397 let aad = b"test";
398 let cipher = Aes128Gcm::new(&key);
399 let mut buf: Vec<u8> = vec![];
400 let tag = cipher.encrypt_in_place(&mut buf, &nonce, aad);
401 let tag_bytes: [u8; 16] = tag.as_ref().try_into().unwrap();
402 cipher
403 .decrypt_in_place(&mut buf, &nonce, aad, &tag_bytes)
404 .expect("decrypt failed");
405 }
406
407 #[test]
408 fn aes128_gcm_tag_mismatch_returns_error() {
409 let key = [0u8; 16];
410 let nonce = [0u8; 12];
411 let cipher = Aes128Gcm::new(&key);
412 let mut buf = b"hello world".to_vec();
413 let tag = cipher.encrypt_in_place(&mut buf, &nonce, &[]);
414 let mut bad_tag: [u8; 16] = tag.as_ref().try_into().unwrap();
415 bad_tag[0] ^= 0xff;
416 let mut buf2 = buf.clone();
417 assert!(cipher.0.decrypt_in_place(&mut buf2, &nonce, &[], &bad_tag).is_err());
418 }
419
420 #[test]
421 fn aes128_gcm_nist_vectors() {
422 for v in NIST_GCM_128_VECTORS.iter() {
423 run_gcm_vector(v);
424 }
425 }
426
427 #[test]
428 fn aes128_block_encrypt_k0_j0() {
429 let key = [0u8; 16];
430 let j0: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
431 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
432 let ct = encrypt_block::<11>(&rk, &j0);
433 let expected = hex::decode_array::<16>(b"58e2fccefa7e3061367f1d57a4e7455a").unwrap();
434 assert_eq!(ct, expected, "AES(K=0, J0=0...01) mismatch");
435 }
436
437 #[test]
438 fn aes128_zero_key_zero_pt_vector() {
439 let key = [0u8; 16];
440 let pt = [0u8; 16];
441 let rk: [[u8; 16]; 11] = expand_key::<11>(&key);
442 let ct = encrypt_block::<11>(&rk, &pt);
443 let ct_hex = hex::encode(ct);
444 assert_eq!(ct_hex, "66e94bd4ef8a2c3b884cfa59ca342b2e", "AES-128 K=0 P=0 encrypt failed");
445 }
446
447 #[test]
448 fn wycheproof_gcm_vectors() {
449 let data: serde_json::Value =
450 serde_json::from_str(include_str!("../../testdata/wycheproof/testvectors_v1/aes_gcm_test.json")).unwrap();
451 let mut valid_tested = 0u64;
452 let mut invalid_tested = 0u64;
453 for group in data["testGroups"].as_array().unwrap() {
454 if group["keySize"].as_u64() != Some(128) {
455 continue;
456 }
457 if group["ivSize"].as_u64() != Some(96) {
458 continue;
459 }
460 if group["tagSize"].as_u64() != Some(128) {
461 continue;
462 }
463 for test in group["tests"].as_array().unwrap() {
464 let key_hex = test["key"].as_str().unwrap();
465 let iv_hex = test["iv"].as_str().unwrap();
466 let msg_hex = test["msg"].as_str().unwrap();
467 let aad_hex = test["aad"].as_str().unwrap();
468 let ct_hex = test["ct"].as_str().unwrap();
469 let tag_hex = test["tag"].as_str().unwrap();
470 let result = test["result"].as_str().unwrap();
471
472 let key = hex::decode_array::<16>(key_hex.as_bytes()).unwrap();
473 let nonce = hex::decode_array::<12>(iv_hex.as_bytes()).unwrap();
474 let expected_ct = hex::decode(ct_hex).unwrap();
475 let expected_tag = hex::decode_array::<16>(tag_hex.as_bytes()).unwrap();
476 let pt = hex::decode(msg_hex).unwrap();
477 let aad = hex::decode(aad_hex).unwrap();
478
479 let cipher = Aes128Gcm::new(&key);
480
481 if result == "valid" {
482 let mut buf = pt.clone();
483 let tag = cipher.encrypt_in_place(&mut buf, &nonce, &aad);
484 assert_eq!(buf, expected_ct, "wycheproof tcId={} ct mismatch", test["tcId"]);
485 assert_eq!(tag.as_ref(), &expected_tag[..], "wycheproof tcId={} tag mismatch", test["tcId"]);
486
487 let mut buf2 = expected_ct.clone();
488 cipher
489 .decrypt_in_place(&mut buf2, &nonce, &aad, &expected_tag[..])
490 .expect("wycheproof decrypt failed");
491 assert_eq!(buf2, pt, "wycheproof tcId={} pt mismatch", test["tcId"]);
492 valid_tested += 1;
493 } else {
494 let mut buf = expected_ct.clone();
495 let result = cipher.decrypt_in_place(&mut buf, &nonce, &aad, &expected_tag[..]);
496 assert!(result.is_err(), "wycheproof tcId={} expected invalid but passed", test["tcId"]);
497 invalid_tested += 1;
498 }
499 }
500 }
501 assert!(valid_tested > 0, "no valid AES-128-GCM wycheproof tests were run");
502 assert!(invalid_tested > 0, "no invalid AES-128-GCM wycheproof tests were run");
503 }
504}
505
506#[cfg(test)]
507mod tests_256 {
508 use hex;
509
510 use super::*;
511 use crate::Aead;
512
513 include!("aes_gcm_256_vectors.rs");
514
515 fn run_gcm_vector_soft(v: &GcmVector) {
516 let key: [u8; 32] = hex::decode_array::<32>(v.key.as_bytes()).unwrap();
517 let nonce: [u8; 12] = hex::decode_array::<12>(v.nonce.as_bytes()).unwrap();
518 let pt = hex::decode(v.pt).unwrap();
519 let aad = hex::decode(v.aad).unwrap();
520 let expected_ct = hex::decode(v.ct).unwrap();
521 let expected_tag: [u8; 16] = hex::decode_array::<16>(v.tag.as_bytes()).unwrap();
522 let round_keys = expand_key(&key);
523 let h = encrypt_block(&round_keys, &[0u8; 16]);
524
525 let cipher = Aes256Gcm::new(&key);
526
527 let mut buf = pt.clone();
528 let tag = cipher.0.encrypt_in_place_soft(&mut buf, &round_keys, &h, &nonce, &aad);
529 assert_eq!(buf, expected_ct, "ciphertext mismatch for key={}", v.key);
530 assert_eq!(tag.as_ref(), &expected_tag[..], "tag mismatch for key={}", v.key);
531
532 let mut buf2 = expected_ct.clone();
533 cipher
534 .0
535 .decrypt_in_place_soft(&mut buf2, &round_keys, &h, &expected_tag, &nonce, &aad)
536 .expect("decrypt failed");
537 assert_eq!(buf2, pt, "plaintext mismatch after decrypt for key={}", v.key);
538 }
539
540 #[test]
541 fn nist_gcm_test_vectors_soft() {
542 for v in NIST_GCM_VECTORS.iter().chain(EXTRA_GCM_VECTORS.iter()) {
543 run_gcm_vector_soft(v);
544 }
545 }
546
547 #[test]
548 fn gcm_tag_mismatch_returns_error_soft() {
549 let key = [0u8; 32];
550 let nonce = [0u8; 12];
551 let cipher = Aes256Gcm::new(&key);
552 let mut buf = b"hello world".to_vec();
553 let tag = cipher.encrypt_in_place(&mut buf, &nonce, &[]);
554 let mut bad_tag: [u8; 16] = tag.as_ref().try_into().unwrap();
555 bad_tag[0] ^= 0xff;
556 let mut buf2 = buf.clone();
557 assert!(cipher.decrypt_in_place(&mut buf2, &bad_tag, &nonce, &[]).is_err());
558 }
559
560 #[test]
561 fn gcm_encrypt_decrypt_large_soft() {
562 let key = [0xabu8; 32];
563 let nonce = [0x01u8; 12];
564 let aad = b"additional data";
565 let plaintext: Vec<u8> = (0u8..=255u8).cycle().take(1024).collect();
566 let round_keys = expand_key(&key);
567 let h = encrypt_block(&round_keys, &[0u8; 16]);
568
569 let cipher = Aes256Gcm::new(&key);
570 let mut buf = plaintext.clone();
571 let tag = cipher.0.encrypt_in_place_soft(&mut buf, &round_keys, &h, &nonce, aad);
572 let tag_bytes: [u8; 16] = tag.as_ref().try_into().unwrap();
573 cipher
574 .0
575 .decrypt_in_place_soft(&mut buf, &round_keys, &h, &tag_bytes, &nonce, aad)
576 .expect("decrypt failed");
577 assert_eq!(buf, plaintext);
578 }
579
580 #[test]
581 fn gcm_empty_plaintext_nonempty_aad_soft() {
582 let key: [u8; 32] =
583 hex::decode_array::<32>(b"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308").unwrap();
584 let nonce: [u8; 12] = hex::decode_array::<12>(b"cafebabefacedbaddecaf888").unwrap();
585 let aad = hex::decode("feedfacedeadbeeffeedfacedeadbeef").unwrap();
586 let round_keys = expand_key(&key);
587 let h = encrypt_block(&round_keys, &[0u8; 16]);
588 let cipher = Aes256Gcm::new(&key);
589 let mut buf: Vec<u8> = vec![];
590 let tag = cipher.0.encrypt_in_place_soft(&mut buf, &round_keys, &h, &nonce, &aad);
591 let tag_bytes: [u8; 16] = tag.as_ref().try_into().unwrap();
592 cipher
593 .0
594 .decrypt_in_place_soft(&mut buf, &round_keys, &h, &tag_bytes, &nonce, &aad)
595 .expect("decrypt failed");
596 }
597
598 #[test]
599 fn nist_gcm_test_vectors_dispatch() {
600 for v in NIST_GCM_VECTORS.iter().chain(EXTRA_GCM_VECTORS.iter()) {
601 let key: [u8; 32] = hex::decode_array::<32>(v.key.as_bytes()).unwrap();
602 let nonce: [u8; 12] = hex::decode_array::<12>(v.nonce.as_bytes()).unwrap();
603 let pt = hex::decode(v.pt).unwrap();
604 let aad = hex::decode(v.aad).unwrap();
605 let expected_ct = hex::decode(v.ct).unwrap();
606 let expected_tag: [u8; 16] = hex::decode_array::<16>(v.tag.as_bytes()).unwrap();
607
608 let cipher = Aes256Gcm::new(&key);
609
610 let mut buf = pt.clone();
611 let tag = cipher.encrypt_in_place(&mut buf, &nonce[..], &aad);
612 assert_eq!(&buf[..], &expected_ct[..], "dispatch ciphertext mismatch key={}", v.key);
613 assert_eq!(tag.as_ref(), &expected_tag[..], "dispatch tag mismatch key={}", v.key);
614
615 let mut buf2 = expected_ct.clone();
616 cipher
617 .decrypt_in_place(&mut buf2, &nonce[..], &aad, &expected_tag)
618 .expect("dispatch decrypt failed");
619 assert_eq!(buf2, pt);
620 }
621 }
622
623 #[test]
624 fn wycheproof_gcm_vectors() {
625 let data: serde_json::Value =
626 serde_json::from_str(include_str!("../../testdata/wycheproof/testvectors_v1/aes_gcm_test.json")).unwrap();
627 let mut valid_tested = 0u64;
628 let mut invalid_tested = 0u64;
629 for group in data["testGroups"].as_array().unwrap() {
630 if group["keySize"].as_u64() != Some(256) {
631 continue;
632 }
633 if group["ivSize"].as_u64() != Some(96) {
634 continue;
635 }
636 if group["tagSize"].as_u64() != Some(128) {
637 continue;
638 }
639 for test in group["tests"].as_array().unwrap() {
640 let key_hex = test["key"].as_str().unwrap();
641 let iv_hex = test["iv"].as_str().unwrap();
642 let msg_hex = test["msg"].as_str().unwrap();
643 let aad_hex = test["aad"].as_str().unwrap();
644 let ct_hex = test["ct"].as_str().unwrap();
645 let tag_hex = test["tag"].as_str().unwrap();
646 let result = test["result"].as_str().unwrap();
647
648 let key = hex::decode_array::<32>(key_hex.as_bytes()).unwrap();
649 let nonce = hex::decode_array::<12>(iv_hex.as_bytes()).unwrap();
650 let expected_ct = hex::decode(ct_hex).unwrap();
651 let expected_tag = hex::decode_array::<16>(tag_hex.as_bytes()).unwrap();
652 let pt = hex::decode(msg_hex).unwrap();
653 let aad = hex::decode(aad_hex).unwrap();
654
655 let cipher = Aes256Gcm::new(&key);
656
657 if result == "valid" {
658 let mut buf = pt.clone();
659 let tag = cipher.encrypt_in_place(&mut buf, &nonce[..], &aad);
660 assert_eq!(buf, expected_ct, "wycheproof GCM tcId={} ct mismatch", test["tcId"]);
661 assert_eq!(
662 tag.as_ref(),
663 &expected_tag[..],
664 "wycheproof GCM tcId={} tag mismatch",
665 test["tcId"]
666 );
667
668 let mut buf2 = expected_ct.clone();
669 cipher
670 .decrypt_in_place(&mut buf2, &nonce[..], &aad, &expected_tag[..])
671 .expect("wycheproof GCM decrypt failed");
672 assert_eq!(buf2, pt, "wycheproof GCM tcId={} pt mismatch", test["tcId"]);
673 valid_tested += 1;
674 } else {
675 let mut buf = expected_ct.clone();
676 let result = cipher.decrypt_in_place(&mut buf, &nonce[..], &aad, &expected_tag[..]);
677 assert!(
678 result.is_err(),
679 "wycheproof GCM tcId={} expected invalid but passed",
680 test["tcId"]
681 );
682 invalid_tested += 1;
683 }
684 }
685 }
686 assert!(valid_tested > 0, "no valid AES-GCM wycheproof tests were run");
687 assert!(invalid_tested > 0, "no invalid AES-GCM wycheproof tests were run");
688 }
689}