1use crate::AeadError;
8
9#[rustfmt::skip]
12pub(crate) const SBOX: [u8; 256] = [
13 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
14 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
15 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
16 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
17 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
18 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
19 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
20 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
21 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
22 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
23 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
24 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
25 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
26 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
27 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
28 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
29];
30
31#[rustfmt::skip]
32const SBOX_INV: [u8; 256] = [
33 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
34 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
35 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
36 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
37 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
38 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
39 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
40 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
41 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
42 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
43 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
44 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
45 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
46 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
47 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
48 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
49];
50
51const RCON: [u8; 11] = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
53
54pub(crate) type RoundKeys = [[u8; 16]; 15];
58
59#[inline(always)]
60fn rot_word(w: [u8; 4]) -> [u8; 4] {
61 [w[1], w[2], w[3], w[0]]
62}
63
64#[inline(always)]
65fn sub_word(w: [u8; 4]) -> [u8; 4] {
66 [
67 SBOX[w[0] as usize],
68 SBOX[w[1] as usize],
69 SBOX[w[2] as usize],
70 SBOX[w[3] as usize],
71 ]
72}
73
74pub(crate) fn key_expand(key: &[u8; 32]) -> RoundKeys {
76 let mut w = [[0u8; 4]; 60];
78
79 for i in 0..8 {
80 w[i] = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]];
81 }
82
83 for i in 8..60 {
84 let mut temp = w[i - 1];
85 if i % 8 == 0 {
86 temp = sub_word(rot_word(temp));
87 temp[0] ^= RCON[i / 8];
88 } else if i % 8 == 4 {
89 temp = sub_word(temp);
90 }
91 w[i] = [
92 w[i - 8][0] ^ temp[0],
93 w[i - 8][1] ^ temp[1],
94 w[i - 8][2] ^ temp[2],
95 w[i - 8][3] ^ temp[3],
96 ];
97 }
98
99 let mut rk = [[0u8; 16]; 15];
100 for i in 0..15 {
101 for j in 0..4 {
102 rk[i][4 * j..4 * j + 4].copy_from_slice(&w[4 * i + j]);
103 }
104 }
105 rk
106}
107
108#[inline(always)]
111fn xtime(a: u8) -> u8 {
112 let hi = a & 0x80;
113 let b = a << 1;
114 if hi != 0 { b ^ 0x1b } else { b }
115}
116
117#[inline(always)]
118fn add_round_key(state: &mut [u8; 16], rk: &[u8; 16]) {
119 for i in 0..16 {
120 state[i] ^= rk[i];
121 }
122}
123
124#[inline(always)]
125fn sub_bytes(state: &mut [u8; 16]) {
126 for b in state.iter_mut() {
127 *b = SBOX[*b as usize];
128 }
129}
130
131#[inline(always)]
133fn shift_rows(s: &mut [u8; 16]) {
134 let t = *s;
135 s[1] = t[5];
138 s[5] = t[9];
139 s[9] = t[13];
140 s[13] = t[1];
141 s[2] = t[10];
143 s[6] = t[14];
144 s[10] = t[2];
145 s[14] = t[6];
146 s[3] = t[15];
148 s[7] = t[3];
149 s[11] = t[7];
150 s[15] = t[11];
151}
152
153#[inline(always)]
155fn mix_col(s: &mut [u8; 16], col: usize) {
156 let i = col * 4;
157 let s0 = s[i];
158 let s1 = s[i + 1];
159 let s2 = s[i + 2];
160 let s3 = s[i + 3];
161 s[i] = xtime(s0) ^ xtime(s1) ^ s1 ^ s2 ^ s3;
162 s[i + 1] = s0 ^ xtime(s1) ^ xtime(s2) ^ s2 ^ s3;
163 s[i + 2] = s0 ^ s1 ^ xtime(s2) ^ xtime(s3) ^ s3;
164 s[i + 3] = xtime(s0) ^ s0 ^ s1 ^ s2 ^ xtime(s3);
165}
166
167#[inline(always)]
168fn mix_columns(state: &mut [u8; 16]) {
169 mix_col(state, 0);
170 mix_col(state, 1);
171 mix_col(state, 2);
172 mix_col(state, 3);
173}
174
175#[inline(always)]
178fn inv_sub_bytes(state: &mut [u8; 16]) {
179 for b in state.iter_mut() {
180 *b = SBOX_INV[*b as usize];
181 }
182}
183
184#[inline(always)]
185fn inv_shift_rows(s: &mut [u8; 16]) {
186 let t = *s;
187 s[1] = t[13];
189 s[5] = t[1];
190 s[9] = t[5];
191 s[13] = t[9];
192 s[2] = t[10];
194 s[6] = t[14];
195 s[10] = t[2];
196 s[14] = t[6];
197 s[3] = t[7];
199 s[7] = t[11];
200 s[11] = t[15];
201 s[15] = t[3];
202}
203
204#[inline(always)]
206fn gmul(mut a: u8, mut b: u8) -> u8 {
207 let mut p = 0u8;
208 for _ in 0..8 {
209 if b & 1 != 0 {
210 p ^= a;
211 }
212 let carry = a & 0x80;
213 a <<= 1;
214 if carry != 0 {
215 a ^= 0x1b;
216 }
217 b >>= 1;
218 }
219 p
220}
221
222#[inline(always)]
223fn inv_mix_col(s: &mut [u8; 16], col: usize) {
224 let i = col * 4;
225 let s0 = s[i];
226 let s1 = s[i + 1];
227 let s2 = s[i + 2];
228 let s3 = s[i + 3];
229 s[i] = gmul(0x0e, s0) ^ gmul(0x0b, s1) ^ gmul(0x0d, s2) ^ gmul(0x09, s3);
230 s[i + 1] = gmul(0x09, s0) ^ gmul(0x0e, s1) ^ gmul(0x0b, s2) ^ gmul(0x0d, s3);
231 s[i + 2] = gmul(0x0d, s0) ^ gmul(0x09, s1) ^ gmul(0x0e, s2) ^ gmul(0x0b, s3);
232 s[i + 3] = gmul(0x0b, s0) ^ gmul(0x0d, s1) ^ gmul(0x09, s2) ^ gmul(0x0e, s3);
233}
234
235#[inline(always)]
236fn inv_mix_columns(state: &mut [u8; 16]) {
237 inv_mix_col(state, 0);
238 inv_mix_col(state, 1);
239 inv_mix_col(state, 2);
240 inv_mix_col(state, 3);
241}
242
243pub(crate) fn encrypt_block(rk: &RoundKeys, block: &[u8; 16]) -> [u8; 16] {
247 let mut state = *block;
248 add_round_key(&mut state, &rk[0]);
249 for r in 1..14 {
250 sub_bytes(&mut state);
251 shift_rows(&mut state);
252 mix_columns(&mut state);
253 add_round_key(&mut state, &rk[r]);
254 }
255 sub_bytes(&mut state);
256 shift_rows(&mut state);
257 add_round_key(&mut state, &rk[14]);
258 state
259}
260
261pub(crate) fn decrypt_block(rk: &RoundKeys, block: &[u8; 16]) -> [u8; 16] {
263 let mut state = *block;
264 add_round_key(&mut state, &rk[14]);
265 for r in (1..14).rev() {
266 inv_shift_rows(&mut state);
267 inv_sub_bytes(&mut state);
268 add_round_key(&mut state, &rk[r]);
269 inv_mix_columns(&mut state);
270 }
271 inv_shift_rows(&mut state);
272 inv_sub_bytes(&mut state);
273 add_round_key(&mut state, &rk[0]);
274 state
275}
276
277#[inline(always)]
291fn gf128_mul_x(v: u128) -> u128 {
292 let carry = v & 1; let shifted = v >> 1;
294 if carry != 0 {
295 shifted ^ (0xe1u128 << 120)
296 } else {
297 shifted
298 }
299}
300
301pub(crate) fn gf128_mul(x: &[u8; 16], h: &[u8; 16]) -> [u8; 16] {
304 let x_val = u128::from_be_bytes(*x);
305 let h_val = u128::from_be_bytes(*h);
306 let mut z = 0u128;
307 let mut v = h_val;
308
309 for k in (0..128u32).rev() {
313 if (x_val >> k) & 1 == 1 {
314 z ^= v;
315 }
316 v = gf128_mul_x(v);
317 }
318 z.to_be_bytes()
319}
320
321#[inline(always)]
326fn ghash_block(state: &mut [u8; 16], h: &[u8; 16], block: &[u8; 16]) {
327 for i in 0..16 {
328 state[i] ^= block[i];
329 }
330 let new = gf128_mul(state, h);
331 *state = new;
332}
333
334fn ghash_update(state: &mut [u8; 16], h: &[u8; 16], data: &[u8]) {
337 let mut chunks = data.chunks_exact(16);
338 for chunk in chunks.by_ref() {
339 let block: [u8; 16] = chunk.try_into().unwrap();
340 ghash_block(state, h, &block);
341 }
342 let rem = chunks.remainder();
343 if !rem.is_empty() {
344 let mut padded = [0u8; 16];
345 padded[..rem.len()].copy_from_slice(rem);
346 ghash_block(state, h, &padded);
347 }
348}
349
350#[inline(always)]
354fn ctr_inc(counter: &mut [u8; 16]) {
355 let c = u32::from_be_bytes(counter[12..16].try_into().unwrap());
356 counter[12..16].copy_from_slice(&c.wrapping_add(1).to_be_bytes());
357}
358
359fn ctr_encrypt(rk: &RoundKeys, in_out: &mut [u8], counter: &mut [u8; 16]) {
362 let n = in_out.len();
363 let mut i = 0;
364 while i + 16 <= n {
365 let ks = encrypt_block(rk, counter);
366 for k in 0..16 {
367 in_out[i + k] ^= ks[k];
368 }
369 ctr_inc(counter);
370 i += 16;
371 }
372 if i < n {
373 let ks = encrypt_block(rk, counter);
374 for k in 0..n - i {
375 in_out[i + k] ^= ks[k];
376 }
377 ctr_inc(counter);
378 }
379}
380
381fn compute_tag(h: &[u8; 16], aad: &[u8], ciphertext: &[u8], ej0: &[u8; 16]) -> [u8; 16] {
386 let mut state = [0u8; 16];
387
388 ghash_update(&mut state, h, aad);
389 ghash_update(&mut state, h, ciphertext);
390
391 let mut len_block = [0u8; 16];
393 len_block[..8].copy_from_slice(&((aad.len() as u64) * 8).to_be_bytes());
394 len_block[8..].copy_from_slice(&((ciphertext.len() as u64) * 8).to_be_bytes());
395 ghash_block(&mut state, h, &len_block);
396
397 for i in 0..16 {
399 state[i] ^= ej0[i];
400 }
401 state
402}
403
404pub struct Aes256Gcm {
411 pub(crate) key: [u8; 32],
412 pub(crate) round_keys: RoundKeys,
413}
414
415impl Aes256Gcm {
416 pub const KEY_SIZE: usize = 32;
417 pub const TAG_SIZE: usize = 16;
418 pub const NONCE_SIZE: usize = 12;
419 const MAX_GCM_LEN: usize = (u32::MAX as usize - 1) * 16;
420
421 pub fn new(key: &[u8; 32]) -> Self {
423 Aes256Gcm {
424 key: *key,
425 round_keys: key_expand(key),
426 }
427 }
428
429 #[inline]
434 #[allow(unreachable_code)]
435 pub fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8; 12], aad: &[u8]) -> [u8; 16] {
436 #[cfg(target_arch = "aarch64")]
438 {
439 use crate::aes::aes256_arm64::encrypt_armv8;
440 unsafe { return encrypt_armv8(&self.key, in_out, nonce, aad) }
441 }
442
443 #[cfg(feature = "std")]
445 {
446 #[cfg(target_arch = "x86_64")]
447 {
448 use crate::aes::aes256_amd64::encrypt_aesni;
449 if std::arch::is_x86_feature_detected!("aes")
450 && std::arch::is_x86_feature_detected!("pclmulqdq")
451 && std::arch::is_x86_feature_detected!("ssse3")
452 && std::arch::is_x86_feature_detected!("sse4.1")
453 {
454 unsafe { return encrypt_aesni(&self.key, in_out, nonce, aad) }
455 }
456 }
457 }
458
459 #[cfg(not(feature = "std"))]
460 {
461 #[cfg(all(
462 target_feature = "aes",
463 target_feature = "pclmulqdq",
464 target_feature = "ssse3",
465 target_feature = "sse4.1"
466 ))]
467 {
468 use crate::aes::aes256_amd64::encrypt_aesni;
469 unsafe {
470 return encrypt_aesni(&self.key, in_out, nonce, aad);
471 }
472 }
473 }
474
475 self.encrypt_in_place_soft(in_out, nonce, aad)
476 }
477
478 #[inline]
482 #[allow(unreachable_code)]
483 pub fn decrypt_in_place(
484 &self,
485 in_out: &mut [u8],
486 tag: &[u8; 16],
487 nonce: &[u8; 12],
488 aad: &[u8],
489 ) -> Result<(), AeadError> {
490 #[cfg(target_arch = "aarch64")]
492 {
493 use crate::aes::aes256_arm64::decrypt_armv8;
494 unsafe { return decrypt_armv8(&self.key, in_out, tag, nonce, aad) }
495 }
496
497 #[cfg(feature = "std")]
498 {
499 #[cfg(target_arch = "x86_64")]
500 {
501 use crate::aes::aes256_amd64::decrypt_aesni;
502 if std::arch::is_x86_feature_detected!("aes")
503 && std::arch::is_x86_feature_detected!("pclmulqdq")
504 && std::arch::is_x86_feature_detected!("ssse3")
505 && std::arch::is_x86_feature_detected!("sse4.1")
506 {
507 unsafe { return decrypt_aesni(&self.key, in_out, tag, nonce, aad) }
508 }
509 }
510 }
511
512 #[cfg(not(feature = "std"))]
513 {
514 #[cfg(all(
515 target_feature = "aes",
516 target_feature = "pclmulqdq",
517 target_feature = "ssse3",
518 target_feature = "sse4.1"
519 ))]
520 {
521 use crate::aes::aes256_amd64::decrypt_aesni;
522 unsafe {
523 return decrypt_aesni(&self.key, in_out, tag, nonce, aad);
524 }
525 }
526 }
527
528 self.decrypt_in_place_soft(in_out, tag, nonce, aad)
529 }
530
531 pub(crate) fn encrypt_in_place_soft(&self, in_out: &mut [u8], nonce: &[u8; 12], aad: &[u8]) -> [u8; 16] {
533 assert!(
534 in_out.len() <= Self::MAX_GCM_LEN,
535 "GCM plaintext exceeds maximum allowed length (2^32 - 2 blocks)"
536 );
537 let rk = &self.round_keys;
538 let h = encrypt_block(rk, &[0u8; 16]);
539
540 let mut j0 = [0u8; 16];
542 j0[..12].copy_from_slice(nonce);
543 j0[15] = 1;
544
545 let ej0 = encrypt_block(rk, &j0);
546
547 let mut ctr = j0;
549 ctr_inc(&mut ctr);
550
551 ctr_encrypt(rk, in_out, &mut ctr);
552 compute_tag(&h, aad, in_out, &ej0)
553 }
554
555 pub(crate) fn decrypt_in_place_soft(
557 &self,
558 in_out: &mut [u8],
559 tag: &[u8; 16],
560 nonce: &[u8; 12],
561 aad: &[u8],
562 ) -> Result<(), AeadError> {
563 if in_out.len() > Self::MAX_GCM_LEN {
564 return Err(AeadError::InvalidCiphertext);
565 }
566 let rk = &self.round_keys;
567 let h = encrypt_block(rk, &[0u8; 16]);
568
569 let mut j0 = [0u8; 16];
570 j0[..12].copy_from_slice(nonce);
571 j0[15] = 1;
572
573 let ej0 = encrypt_block(rk, &j0);
574
575 let expected_tag = compute_tag(&h, aad, in_out, &ej0);
577
578 let mut diff = 0u8;
580 for i in 0..16 {
581 diff |= expected_tag[i] ^ tag[i];
582 }
583 if diff != 0 {
584 return Err(AeadError::InvalidCiphertext);
585 }
586
587 let mut ctr = j0;
588 ctr_inc(&mut ctr);
589 ctr_encrypt(rk, in_out, &mut ctr);
590
591 Ok(())
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 fn hb<const N: usize>(s: &str) -> [u8; N] {
604 let v = hex::decode(s).unwrap();
605 assert_eq!(v.len(), N, "wrong hex length for '{s}'");
606 v.try_into().unwrap()
607 }
608
609 #[test]
614 fn fips197_aes256_encrypt() {
615 let key: [u8; 32] = hb("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
617 let pt: [u8; 16] = hb("00112233445566778899aabbccddeeff");
618 let ct_expected: [u8; 16] = hb("8ea2b7ca516745bfeafc49904b496089");
619
620 let rk = key_expand(&key);
621 let ct = encrypt_block(&rk, &pt);
622 assert_eq!(ct, ct_expected);
623 }
624
625 #[test]
626 fn fips197_aes256_decrypt() {
627 let key: [u8; 32] = hb("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
628 let ct: [u8; 16] = hb("8ea2b7ca516745bfeafc49904b496089");
629 let pt_expected: [u8; 16] = hb("00112233445566778899aabbccddeeff");
630
631 let rk = key_expand(&key);
632 let pt = decrypt_block(&rk, &ct);
633 assert_eq!(pt, pt_expected);
634 }
635
636 #[test]
638 fn nist_sp800_38a_aes256_ecb() {
639 let key: [u8; 32] = hb("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
640
641 let blocks: &[([u8; 16], [u8; 16])] = &[
642 (hb("6bc1bee22e409f96e93d7e117393172a"), hb("f3eed1bdb5d2a03c064b5a7e3db181f8")),
643 (hb("ae2d8a571e03ac9c9eb76fac45af8e51"), hb("591ccb10d410ed26dc5ba74a31362870")),
644 (hb("30c81c46a35ce411e5fbc1191a0a52ef"), hb("b6ed21b99ca6f4f9f153e7b1beafed1d")),
645 (hb("f69f2445df4f9b17ad2b417be66c3710"), hb("23304b7a39f9f3ff067d8d8f9e24ecc7")),
646 ];
647
648 let rk = key_expand(&key);
649 for (pt, ct) in blocks {
650 assert_eq!(encrypt_block(&rk, pt), *ct);
651 assert_eq!(decrypt_block(&rk, ct), *pt);
652 }
653 }
654
655 #[test]
657 fn aes256_kat_vectors() {
658 let vectors: &[([u8; 32], [u8; 16], [u8; 16])] = &[
660 ([0u8; 32], [0u8; 16], hb("dc95c078a2408989ad48a21492842087")),
662 (
664 hb("0101010101010101010101010101010101010101010101010101010101010101"),
665 [0u8; 16],
666 hb("7298caa565031eadc6ce23d23ea66378"),
667 ),
668 ([0xff; 32], [0u8; 16], hb("4bf85f1b5d54adbc307b0a048389adcb")),
670 ];
671
672 for (key, pt, ct_expected) in vectors {
673 let rk = key_expand(key);
674 let ct = encrypt_block(&rk, pt);
675 assert_eq!(ct, *ct_expected, "key={}", hex::encode(key));
676 let pt2 = decrypt_block(&rk, &ct);
677 assert_eq!(pt2, *pt, "round-trip failed");
678 }
679 }
680
681 #[test]
682 fn encrypt_decrypt_roundtrip_random() {
683 let key: [u8; 32] = hb("deadbeefcafebabedeadbeefcafebabe0011223344556677deadbeefcafebabe");
684 let rk = key_expand(&key);
685 for seed in 0u8..=255 {
686 let pt = [seed; 16];
687 let ct = encrypt_block(&rk, &pt);
688 let pt2 = decrypt_block(&rk, &ct);
689 assert_eq!(pt2, pt);
690 }
691 }
692
693 #[test]
696 fn gf128_mul_zero() {
697 let h = [
698 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e,
699 ];
700 let zero = [0u8; 16];
701 assert_eq!(gf128_mul(&zero, &h), zero);
702 assert_eq!(gf128_mul(&h, &zero), zero);
703 }
704
705 #[test]
706 fn gf128_mul_commutativity() {
707 let a: [u8; 16] = hb("66e94bd4ef8a2c3b884cfa59ca342b2e");
708 let b: [u8; 16] = hb("feedfacedeadbeeffeedfacedeadbeef");
709 assert_eq!(gf128_mul(&a, &b), gf128_mul(&b, &a));
710 }
711
712 #[test]
714 fn gf128_mul_nist_tv2() {
715 let h: [u8; 16] = hb("66e94bd4ef8a2c3b884cfa59ca342b2e");
721 let x: [u8; 16] = hb("feedfacedeadbeeffeedfacedeadbeef");
722 let expected: [u8; 16] = hb("88eddca9968dec8b9c952d6ae0290a82");
724 assert_eq!(gf128_mul(&x, &h), expected);
725 }
726
727 struct GcmVector {
730 key: &'static str,
731 nonce: &'static str,
732 pt: &'static str,
733 aad: &'static str,
734 ct: &'static str,
735 tag: &'static str,
736 }
737
738 const NIST_GCM_VECTORS: &[GcmVector] = &[
739 GcmVector {
741 key: "0000000000000000000000000000000000000000000000000000000000000000",
742 nonce: "000000000000000000000000",
743 pt: "",
744 aad: "",
745 ct: "",
746 tag: "530f8afbc74536b9a963b4f1c4cb738b",
747 },
748 GcmVector {
750 key: "0000000000000000000000000000000000000000000000000000000000000000",
751 nonce: "000000000000000000000000",
752 pt: "00000000000000000000000000000000",
753 aad: "",
754 ct: "cea7403d4d606b6e074ec5d3baf39d18",
755 tag: "d0d1c8a799996bf0265b98b5d48ab919",
756 },
757 GcmVector {
759 key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
760 nonce: "cafebabefacedbaddecaf888",
761 pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
762 aad: "",
763 ct: "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
764 tag: "b094dac5d93471bdec1a502270e3cc6c",
765 },
766 GcmVector {
768 key: "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
769 nonce: "cafebabefacedbaddecaf888",
770 pt: "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
771 aad: "feedfacedeadbeeffeedfacedeadbeefabaddad2",
772 ct: "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
773 tag: "76fc6ece0f4e1768cddf8853bb2d551b",
774 },
775 ];
776
777 include!("aes256_gcm_vectors.rs");
778
779 fn run_gcm_vector_soft(v: &GcmVector) {
780 let key: [u8; 32] = hb(v.key);
781 let nonce: [u8; 12] = hb(v.nonce);
782 let pt = hex::decode(v.pt).unwrap();
783 let aad = hex::decode(v.aad).unwrap();
784 let expected_ct = hex::decode(v.ct).unwrap();
785 let expected_tag: [u8; 16] = hb(v.tag);
786
787 let cipher = Aes256Gcm::new(&key);
788
789 let mut buf = pt.clone();
791 let tag = cipher.encrypt_in_place_soft(&mut buf, &nonce, &aad);
792 assert_eq!(buf, expected_ct, "ciphertext mismatch for key={}", v.key);
793 assert_eq!(tag, expected_tag, "tag mismatch for key={}", v.key);
794
795 let mut buf2 = expected_ct.clone();
797 cipher
798 .decrypt_in_place_soft(&mut buf2, &expected_tag, &nonce, &aad)
799 .expect("decrypt failed");
800 assert_eq!(buf2, pt, "plaintext mismatch after decrypt for key={}", v.key);
801 }
802
803 #[test]
804 fn nist_gcm_test_vectors_soft() {
805 for v in NIST_GCM_VECTORS.iter().chain(EXTRA_GCM_VECTORS.iter()) {
806 run_gcm_vector_soft(v);
807 }
808 }
809
810 #[test]
811 fn gcm_tag_mismatch_returns_error_soft() {
812 let key = [0u8; 32];
813 let nonce = [0u8; 12];
814 let cipher = Aes256Gcm::new(&key);
815 let mut buf = b"hello world".to_vec();
816 let tag = cipher.encrypt_in_place_soft(&mut buf, &nonce, &[]);
817 let mut bad_tag = tag;
819 bad_tag[0] ^= 0xff;
820 let mut buf2 = buf.clone();
821 assert!(cipher.decrypt_in_place_soft(&mut buf2, &bad_tag, &nonce, &[]).is_err());
822 }
823
824 #[test]
825 fn gcm_encrypt_decrypt_large_soft() {
826 let key = [0xabu8; 32];
827 let nonce = [0x01u8; 12];
828 let aad = b"additional data";
829 let plaintext: Vec<u8> = (0u8..=255u8).cycle().take(1024).collect();
830
831 let cipher = Aes256Gcm::new(&key);
832 let mut buf = plaintext.clone();
833 let tag = cipher.encrypt_in_place_soft(&mut buf, &nonce, aad);
834 cipher
835 .decrypt_in_place_soft(&mut buf, &tag, &nonce, aad)
836 .expect("decrypt failed");
837 assert_eq!(buf, plaintext);
838 }
839
840 #[test]
841 fn gcm_empty_plaintext_nonempty_aad_soft() {
842 let key: [u8; 32] = hb("feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308");
843 let nonce: [u8; 12] = hb("cafebabefacedbaddecaf888");
844 let aad = hex::decode("feedfacedeadbeeffeedfacedeadbeef").unwrap();
845 let cipher = Aes256Gcm::new(&key);
846 let mut buf: Vec<u8> = vec![];
847 let tag = cipher.encrypt_in_place_soft(&mut buf, &nonce, &aad);
848 cipher
849 .decrypt_in_place_soft(&mut buf, &tag, &nonce, &aad)
850 .expect("decrypt failed");
851 }
852
853 #[test]
856 fn nist_gcm_test_vectors_dispatch() {
857 for v in NIST_GCM_VECTORS.iter().chain(EXTRA_GCM_VECTORS.iter()) {
858 let key: [u8; 32] = hb(v.key);
859 let nonce: [u8; 12] = hb(v.nonce);
860 let pt = hex::decode(v.pt).unwrap();
861 let aad = hex::decode(v.aad).unwrap();
862 let expected_ct = hex::decode(v.ct).unwrap();
863 let expected_tag: [u8; 16] = hb(v.tag);
864
865 let cipher = Aes256Gcm::new(&key);
866
867 let mut buf = pt.clone();
868 let tag = cipher.encrypt_in_place(&mut buf, &nonce, &aad);
869 assert_eq!(buf, expected_ct, "dispatch ciphertext mismatch key={}", v.key);
870 assert_eq!(tag, expected_tag, "dispatch tag mismatch key={}", v.key);
871
872 let mut buf2 = expected_ct.clone();
873 cipher
874 .decrypt_in_place(&mut buf2, &expected_tag, &nonce, &aad)
875 .expect("dispatch decrypt failed");
876 assert_eq!(buf2, pt);
877 }
878 }
879
880 #[test]
883 fn wycheproof_gcm_vectors() {
884 let data: serde_json::Value =
885 serde_json::from_str(include_str!("../../testdata/wycheproof/testvectors_v1/aes_gcm_test.json")).unwrap();
886 let mut valid_tested = 0u64;
887 let mut invalid_tested = 0u64;
888 for group in data["testGroups"].as_array().unwrap() {
889 if group["keySize"].as_u64() != Some(256) {
890 continue;
891 }
892 if group["ivSize"].as_u64() != Some(96) {
893 continue;
894 }
895 if group["tagSize"].as_u64() != Some(128) {
896 continue;
897 }
898 for test in group["tests"].as_array().unwrap() {
899 let key_hex = test["key"].as_str().unwrap();
900 let iv_hex = test["iv"].as_str().unwrap();
901 let msg_hex = test["msg"].as_str().unwrap();
902 let aad_hex = test["aad"].as_str().unwrap();
903 let ct_hex = test["ct"].as_str().unwrap();
904 let tag_hex = test["tag"].as_str().unwrap();
905 let result = test["result"].as_str().unwrap();
906
907 let key = hb::<32>(key_hex);
908 let nonce = hb::<12>(iv_hex);
909 let expected_ct = hex::decode(ct_hex).unwrap();
910 let expected_tag = hb::<16>(tag_hex);
911 let pt = hex::decode(msg_hex).unwrap();
912 let aad = hex::decode(aad_hex).unwrap();
913
914 let cipher = Aes256Gcm::new(&key);
915
916 if result == "valid" {
917 let mut buf = pt.clone();
918 let tag = cipher.encrypt_in_place(&mut buf, &nonce, &aad);
919 assert_eq!(buf, expected_ct, "wycheproof GCM tcId={} ct mismatch", test["tcId"]);
920 assert_eq!(tag, expected_tag, "wycheproof GCM tcId={} tag mismatch", test["tcId"]);
921
922 let mut buf2 = expected_ct.clone();
923 cipher
924 .decrypt_in_place(&mut buf2, &expected_tag, &nonce, &aad)
925 .expect("wycheproof GCM decrypt failed");
926 assert_eq!(buf2, pt, "wycheproof GCM tcId={} pt mismatch", test["tcId"]);
927 valid_tested += 1;
928 } else {
929 let mut buf = expected_ct.clone();
930 let result = cipher.decrypt_in_place(&mut buf, &expected_tag, &nonce, &aad);
931 assert!(
932 result.is_err(),
933 "wycheproof GCM tcId={} expected invalid but passed",
934 test["tcId"]
935 );
936 invalid_tested += 1;
937 }
938 }
939 }
940 assert!(valid_tested > 0, "no valid AES-GCM wycheproof tests were run");
941 assert!(invalid_tested > 0, "no invalid AES-GCM wycheproof tests were run");
942 }
943}