1#![allow(deprecated)]
2#[allow(deprecated)]
42use aes::Aes128;
43use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
44use core::marker::PhantomData;
45
46use crate::common::{BLOCK_LENGTH, Direction, Error, xor_blocks};
47use crate::hctr2::AesCipher;
48
49pub const HASH_BLOCK_LENGTH: usize = 32;
51
52type Elem = [u64; 4];
53
54#[inline]
59fn bmul64(x: u64, y: u64) -> u128 {
60 const M0: u128 = 0x1111_1111_1111_1111_1111_1111_1111_1111;
61 const M1: u128 = M0 << 1;
62 const M2: u128 = M0 << 2;
63 const M3: u128 = M0 << 3;
64
65 let x0 = (x as u128) & M0;
66 let x1 = (x as u128) & M1;
67 let x2 = (x as u128) & M2;
68 let x3 = (x as u128) & M3;
69 let y0 = (y as u128) & M0;
70 let y1 = (y as u128) & M1;
71 let y2 = (y as u128) & M2;
72 let y3 = (y as u128) & M3;
73
74 let z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
75 let z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
76 let z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
77 let z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
78
79 (z0 & M0) | (z1 & M1) | (z2 & M2) | (z3 & M3)
80}
81
82fn gf_mul(a: &Elem, b: &Elem) -> Elem {
86 let mut t = [0u64; 8];
87 for i in 0..4 {
88 for j in 0..4 {
89 let p = bmul64(a[i], b[j]);
90 t[i + j] ^= p as u64;
91 t[i + j + 1] ^= (p >> 64) as u64;
92 }
93 }
94
95 let hi = [t[4], t[5], t[6], t[7]];
97 let mut res = [t[0], t[1], t[2], t[3]];
98 let mut overflow: u64 = 0;
99 for k in 0..4 {
100 res[k] ^= hi[k];
101 }
102 for s in [2u32, 5, 10] {
103 let mut prev: u64 = 0;
104 for k in 0..4 {
105 res[k] ^= (hi[k] << s) | (prev >> (64 - s));
106 prev = hi[k];
107 }
108 overflow ^= hi[3] >> (64 - s);
109 }
110 res[0] ^= overflow ^ (overflow << 2) ^ (overflow << 5) ^ (overflow << 10);
112 res
113}
114
115#[inline]
116fn elem_from_bytes(bytes: &[u8; HASH_BLOCK_LENGTH]) -> Elem {
117 let mut e = [0u64; 4];
118 for (i, limb) in e.iter_mut().enumerate() {
119 *limb = u64::from_le_bytes(bytes[i * 8..(i + 1) * 8].try_into().unwrap());
120 }
121 e
122}
123
124#[inline]
125fn elem_to_bytes(e: &Elem) -> [u8; HASH_BLOCK_LENGTH] {
126 let mut bytes = [0u8; HASH_BLOCK_LENGTH];
127 for (i, limb) in e.iter().enumerate() {
128 bytes[i * 8..(i + 1) * 8].copy_from_slice(&limb.to_le_bytes());
129 }
130 bytes
131}
132
133#[inline]
134fn elem_xor(a: &Elem, b: &Elem) -> Elem {
135 [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]]
136}
137
138fn hash2n(key: &Elem, tweak: &[u8], msg: &[u8]) -> [u8; HASH_BLOCK_LENGTH] {
143 let tweak_len_bits = tweak.len() * 8;
144 let len_code: u128 = if msg.len().is_multiple_of(HASH_BLOCK_LENGTH) {
145 (2 * tweak_len_bits + 2) as u128
146 } else {
147 (2 * tweak_len_bits + 3) as u128
148 };
149 let mut len_block = [0u8; HASH_BLOCK_LENGTH];
150 len_block[..16].copy_from_slice(&len_code.to_le_bytes());
151
152 let mut acc = [0u64; 4];
153 let mut update = |block: &[u8; HASH_BLOCK_LENGTH]| {
154 acc = gf_mul(&elem_xor(&acc, &elem_from_bytes(block)), key);
155 };
156
157 update(&len_block);
158
159 let mut chunks = tweak.chunks_exact(HASH_BLOCK_LENGTH);
160 for chunk in chunks.by_ref() {
161 update(chunk.try_into().unwrap());
162 }
163 let rem = chunks.remainder();
164 if !rem.is_empty() {
165 let mut block = [0u8; HASH_BLOCK_LENGTH];
166 block[..rem.len()].copy_from_slice(rem);
167 update(&block);
168 }
169
170 let mut chunks = msg.chunks_exact(HASH_BLOCK_LENGTH);
171 for chunk in chunks.by_ref() {
172 update(chunk.try_into().unwrap());
173 }
174 let rem = chunks.remainder();
175 if !rem.is_empty() {
176 let mut block = [0u8; HASH_BLOCK_LENGTH];
177 block[..rem.len()].copy_from_slice(rem);
178 block[rem.len()] = 1;
179 update(&block);
180 }
181
182 elem_to_bytes(&acc)
183}
184
185pub struct Hctr2pp<Aes: AesCipher> {
192 h1: Elem,
193 h2: Elem,
194 h12: Elem,
195 kk: Elem,
196 _aes: PhantomData<Aes>,
197}
198
199#[allow(non_camel_case_types)]
201pub type Hctr2pp_128 = Hctr2pp<Aes128>;
202
203#[allow(non_camel_case_types)]
212pub type Hctr2pp_256 = Hctr2pp<aes::Aes256>;
213
214impl<Aes: AesCipher> Hctr2pp<Aes> {
215 pub const KEY_LENGTH: usize = Aes::KEY_LEN;
217
218 pub const BLOCK_LENGTH: usize = BLOCK_LENGTH;
220
221 pub const MIN_INPUT_LENGTH: usize = BLOCK_LENGTH;
223
224 pub fn new(key: &[u8]) -> Self {
226 debug_assert_eq!(key.len(), Aes::KEY_LEN);
227
228 let ks = Aes::new(Array::from_slice(key));
229 let mut subkeys = [[0u8; BLOCK_LENGTH]; 6];
230 for (i, subkey) in subkeys.iter_mut().enumerate() {
231 let mut block = [0u8; BLOCK_LENGTH];
232 block[0] = (i + 1) as u8;
233 let mut arr = Array::clone_from_slice(&block);
234 ks.encrypt_block(&mut arr);
235 *subkey = arr.as_slice().try_into().unwrap();
236 }
237
238 let pair = |a: &[u8; 16], b: &[u8; 16]| {
239 let mut bytes = [0u8; HASH_BLOCK_LENGTH];
240 bytes[..16].copy_from_slice(a);
241 bytes[16..].copy_from_slice(b);
242 elem_from_bytes(&bytes)
243 };
244 let h1 = pair(&subkeys[0], &subkeys[1]);
245 let h2 = pair(&subkeys[2], &subkeys[3]);
246 let kk = pair(&subkeys[4], &subkeys[5]);
247
248 Self {
249 h1,
250 h2,
251 h12: elem_xor(&h1, &h2),
252 kk,
253 _aes: PhantomData,
254 }
255 }
256
257 pub fn encrypt(
268 &self,
269 plaintext: &[u8],
270 tweak: &[u8],
271 ciphertext: &mut [u8],
272 ) -> Result<(), Error> {
273 self.hctr2pp(plaintext, tweak, ciphertext, Direction::Encrypt)
274 }
275
276 pub fn decrypt(
287 &self,
288 ciphertext: &[u8],
289 tweak: &[u8],
290 plaintext: &mut [u8],
291 ) -> Result<(), Error> {
292 self.hctr2pp(ciphertext, tweak, plaintext, Direction::Decrypt)
293 }
294
295 fn r3(&self, r: &[u8; BLOCK_LENGTH]) -> ([u8; BLOCK_LENGTH], [u8; BLOCK_LENGTH]) {
300 let digest = hash2n(&self.kk, b"", r);
301 (
302 digest[..BLOCK_LENGTH].try_into().unwrap(),
303 digest[BLOCK_LENGTH..].try_into().unwrap(),
304 )
305 }
306
307 fn hctr2pp(
308 &self,
309 src: &[u8],
310 tweak: &[u8],
311 dst: &mut [u8],
312 direction: Direction,
313 ) -> Result<(), Error> {
314 if dst.len() != src.len() {
315 return Err(Error::OutputLengthMismatch);
316 }
317 if src.len() < BLOCK_LENGTH {
318 return Err(Error::InputTooShort);
319 }
320
321 let (hk_in, hk_out) = match direction {
324 Direction::Encrypt => (&self.h1, &self.h2),
325 Direction::Decrypt => (&self.h2, &self.h1),
326 };
327
328 let first: [u8; BLOCK_LENGTH] = src[..BLOCK_LENGTH].try_into().unwrap();
329 let bulk = &src[BLOCK_LENGTH..];
330
331 let x1 = hash2n(hk_in, tweak, bulk);
332 let pp1 = xor_blocks(&first, &x1[..BLOCK_LENGTH].try_into().unwrap());
333 let re: [u8; BLOCK_LENGTH] = x1[BLOCK_LENGTH..].try_into().unwrap();
334
335 let (ue, ve) = self.r3(&re);
336 let mut cc_block = Array::from(xor_blocks(&pp1, &ve));
337 Aes128::new(Array::from_slice(&ue)).encrypt_block(&mut cc_block);
338 let cc = xor_blocks(&cc_block.into(), &ve);
339
340 let rj = hash2n(&self.h12, tweak, &cc);
341 let r: [u8; BLOCK_LENGTH] = rj[..BLOCK_LENGTH].try_into().unwrap();
342 let j: [u8; BLOCK_LENGTH] = rj[BLOCK_LENGTH..].try_into().unwrap();
343
344 let (dst_first, dst_bulk) = dst.split_at_mut(BLOCK_LENGTH);
345 self.ctr_pp(&r, &j, bulk, dst_bulk);
346
347 let x2 = hash2n(hk_out, tweak, dst_bulk);
348 let rd: [u8; BLOCK_LENGTH] = x2[BLOCK_LENGTH..].try_into().unwrap();
349
350 let (ud, vd) = self.r3(&rd);
351 let mut pp2_block = Array::from(xor_blocks(&cc, &vd));
352 aes::Aes128Dec::new(Array::from_slice(&ud)).decrypt_block(&mut pp2_block);
353 let pp2 = xor_blocks(&pp2_block.into(), &vd);
354
355 dst_first.copy_from_slice(&xor_blocks(&pp2, &x2[..BLOCK_LENGTH].try_into().unwrap()));
356
357 Ok(())
358 }
359
360 fn ctr_pp(&self, r: &[u8; BLOCK_LENGTH], j: &[u8; BLOCK_LENGTH], src: &[u8], dst: &mut [u8]) {
362 for (i, (src_chunk, dst_chunk)) in src
363 .chunks(BLOCK_LENGTH)
364 .zip(dst.chunks_mut(BLOCK_LENGTH))
365 .enumerate()
366 {
367 let counter = ((i + 1) as u128).to_le_bytes();
368 let ri = xor_blocks(r, &counter);
369 let ji = xor_blocks(j, &counter);
370
371 let (ui, vi) = self.r3(&ri);
372 let mut block = Array::from(xor_blocks(&ji, &vi));
373 Aes128::new(Array::from_slice(&ui)).encrypt_block(&mut block);
374 let si = xor_blocks(&block.into(), &vi);
375
376 for (k, (d, s)) in dst_chunk.iter_mut().zip(src_chunk.iter()).enumerate() {
377 *d = s ^ si[k];
378 }
379 }
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386
387 fn xorshift(state: &mut u64) -> u64 {
388 *state ^= *state << 13;
389 *state ^= *state >> 7;
390 *state ^= *state << 17;
391 *state
392 }
393
394 fn random_elem(state: &mut u64) -> Elem {
395 [
396 xorshift(state),
397 xorshift(state),
398 xorshift(state),
399 xorshift(state),
400 ]
401 }
402
403 fn slow_mul(a: &Elem, b: &Elem) -> Elem {
405 let mut res = [0u64; 4];
406 let mut cur = *a;
407 for limb in b.iter() {
408 for bit in 0..64 {
409 if (limb >> bit) & 1 == 1 {
410 res = elem_xor(&res, &cur);
411 }
412 let carry = cur[3] >> 63;
414 cur[3] = (cur[3] << 1) | (cur[2] >> 63);
415 cur[2] = (cur[2] << 1) | (cur[1] >> 63);
416 cur[1] = (cur[1] << 1) | (cur[0] >> 63);
417 cur[0] = (cur[0] << 1) ^ (carry * 0x425);
418 }
419 }
420 res
421 }
422
423 #[test]
424 fn test_gf_mul_matches_reference() {
425 let mut state = 0x1234_5678_9abc_def0u64;
426 for _ in 0..50 {
427 let a = random_elem(&mut state);
428 let b = random_elem(&mut state);
429 assert_eq!(gf_mul(&a, &b), slow_mul(&a, &b));
430 }
431 }
432
433 #[test]
434 fn test_gf_mul_identity_and_commutativity() {
435 let one: Elem = [1, 0, 0, 0];
436 let mut state = 0xdead_beef_cafe_f00du64;
437 for _ in 0..20 {
438 let a = random_elem(&mut state);
439 let b = random_elem(&mut state);
440 assert_eq!(gf_mul(&a, &one), a);
441 assert_eq!(gf_mul(&a, &b), gf_mul(&b, &a));
442 }
443 }
444
445 #[test]
446 fn test_hash2n_separates_inputs() {
447 let key: Elem = [2, 0, 0, 0];
448 assert_ne!(hash2n(&key, b"", b"a"), hash2n(&key, b"a", b""));
449 assert_ne!(hash2n(&key, b"t", b"m"), hash2n(&key, b"t", b"m\0"));
450 assert_ne!(hash2n(&key, b"", &[0u8; 32]), hash2n(&key, b"", &[0u8; 64]));
451 }
452
453 #[test]
454 fn test_hctr2pp_128_roundtrip() {
455 let key = [0u8; 16];
456 let cipher = Hctr2pp_128::new(&key);
457
458 let plaintext = b"Hello, HCTR2++ World!";
459 let mut ciphertext = vec![0u8; plaintext.len()];
460 let mut decrypted = vec![0u8; plaintext.len()];
461
462 let tweak = b"test tweak";
463
464 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
465 assert_ne!(plaintext.as_slice(), ciphertext.as_slice());
466
467 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
468 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
469 }
470
471 #[test]
472 fn test_hctr2pp_128_roundtrip_all_lengths() {
473 let key: [u8; 16] = core::array::from_fn(|i| (i * 7 + 1) as u8);
474 let cipher = Hctr2pp_128::new(&key);
475 let tweak = b"length sweep";
476
477 let plaintext: Vec<u8> = (0..100).map(|i| (i * 13 + 5) as u8).collect();
478 for len in 16..=plaintext.len() {
479 let mut ciphertext = vec![0u8; len];
480 let mut decrypted = vec![0u8; len];
481 cipher
482 .encrypt(&plaintext[..len], tweak, &mut ciphertext)
483 .unwrap();
484 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
485 assert_eq!(&plaintext[..len], decrypted.as_slice(), "len = {len}");
486 }
487 }
488
489 #[test]
490 fn test_hctr2pp_128_minimum_length() {
491 let key = [0u8; 16];
492 let cipher = Hctr2pp_128::new(&key);
493
494 let plaintext = [0x42u8; 16];
495 let mut ciphertext = [0u8; 16];
496 let mut decrypted = [0u8; 16];
497
498 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
499 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
500
501 assert_eq!(plaintext, decrypted);
502 }
503
504 #[test]
505 fn test_hctr2pp_128_input_too_short() {
506 let key = [0u8; 16];
507 let cipher = Hctr2pp_128::new(&key);
508
509 let plaintext = [0x42u8; 15];
510 let mut ciphertext = [0u8; 15];
511
512 assert_eq!(
513 cipher.encrypt(&plaintext, b"", &mut ciphertext),
514 Err(Error::InputTooShort)
515 );
516 }
517
518 #[test]
519 fn test_hctr2pp_128_different_tweaks() {
520 let key = [0u8; 16];
521 let cipher = Hctr2pp_128::new(&key);
522
523 let plaintext = [0x42u8; 32];
524 let mut ciphertext1 = [0u8; 32];
525 let mut ciphertext2 = [0u8; 32];
526
527 cipher
528 .encrypt(&plaintext, b"tweak1", &mut ciphertext1)
529 .unwrap();
530 cipher
531 .encrypt(&plaintext, b"tweak2", &mut ciphertext2)
532 .unwrap();
533 assert_ne!(ciphertext1, ciphertext2);
534 }
535
536 #[test]
537 fn test_hctr2pp_128_deterministic() {
538 let key: [u8; 16] = core::array::from_fn(|i| i as u8);
539 let cipher1 = Hctr2pp_128::new(&key);
540 let cipher2 = Hctr2pp_128::new(&key);
541
542 let plaintext = [0x55u8; 64];
543 let mut ciphertext1 = [0u8; 64];
544 let mut ciphertext2 = [0u8; 64];
545
546 cipher1.encrypt(&plaintext, b"t", &mut ciphertext1).unwrap();
547 cipher2.encrypt(&plaintext, b"t", &mut ciphertext2).unwrap();
548 assert_eq!(ciphertext1, ciphertext2);
549 }
550
551 #[test]
552 fn test_hctr2pp_128_avalanche() {
553 let key = [7u8; 16];
554 let cipher = Hctr2pp_128::new(&key);
555
556 let plaintext = [0u8; 64];
557 let mut modified = plaintext;
558 modified[63] ^= 1;
559
560 let mut ciphertext1 = [0u8; 64];
561 let mut ciphertext2 = [0u8; 64];
562 cipher.encrypt(&plaintext, b"t", &mut ciphertext1).unwrap();
563 cipher.encrypt(&modified, b"t", &mut ciphertext2).unwrap();
564
565 assert_ne!(ciphertext1[..16], ciphertext2[..16]);
567 assert_ne!(ciphertext1[16..48], ciphertext2[16..48]);
569 }
570
571 #[test]
572 fn test_hctr2pp_128_large_message() {
573 let key = [0u8; 16];
574 let cipher = Hctr2pp_128::new(&key);
575
576 let plaintext = [0xABu8; 1024];
577 let mut ciphertext = [0u8; 1024];
578 let mut decrypted = [0u8; 1024];
579
580 cipher
581 .encrypt(&plaintext, b"large tweak", &mut ciphertext)
582 .unwrap();
583 cipher
584 .decrypt(&ciphertext, b"large tweak", &mut decrypted)
585 .unwrap();
586
587 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
588 }
589
590 #[test]
591 fn test_hctr2pp_256_roundtrip() {
592 let key = [0u8; 32];
593 let cipher = Hctr2pp_256::new(&key);
594
595 let plaintext = b"Hello, HCTR2++-256 World!";
596 let mut ciphertext = vec![0u8; plaintext.len()];
597 let mut decrypted = vec![0u8; plaintext.len()];
598
599 let tweak = b"test tweak 256";
600
601 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
602 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
603
604 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
605 }
606
607 fn unhex(s: &str) -> Vec<u8> {
608 (0..s.len())
609 .step_by(2)
610 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
611 .collect()
612 }
613
614 #[test]
619 fn test_kat_subkeys() {
620 let key: [u8; 16] = core::array::from_fn(|i| i as u8);
621 let cipher = Hctr2pp_128::new(&key);
622
623 let expect = |hex: &str| elem_from_bytes(&unhex(hex).try_into().unwrap());
624 assert_eq!(
625 cipher.h1,
626 expect("e37cd363dd7c87a09aff0e3e60e09c82fb8ae31ba5db9cad97364d8722d47326")
627 );
628 assert_eq!(
629 cipher.h2,
630 expect("8cb899148f1fa8ff9132d0eb15a936f2f08c8d049312eac76f8fa05078178aa1")
631 );
632 assert_eq!(
633 cipher.kk,
634 expect("789dc76ccb52ce1c3db90ecb357af60eeb3ee851461107fec27297b27ad5e563")
635 );
636 }
637
638 #[test]
639 fn test_kat_hash2n() {
640 let key: [u8; 16] = core::array::from_fn(|i| i as u8);
641 let cipher = Hctr2pp_128::new(&key);
642
643 let msg16: [u8; 16] = core::array::from_fn(|i| i as u8);
644 let msg40: [u8; 40] = core::array::from_fn(|i| i as u8);
645 let cases: [(&[u8], &[u8], &str); 4] = [
646 (
647 b"",
648 b"",
649 "c6f9a6c7baf90e4135ff1d7cc0c03905f715c7374ab7395b2f6d9a0e45a8e74c",
650 ),
651 (
652 b"tweak",
653 b"",
654 "3c4414e8acf1f1bc7f9674c74043855751ef29e9513bdcf7fec97f76776ec5d6",
655 ),
656 (
657 b"",
658 &msg16,
659 "6bcd860a4f8467fee40f2ae865cf74f010994a07f5c9b0248be2ffff87f29fad",
660 ),
661 (
662 b"tweak",
663 &msg40,
664 "89e96782de662ce1592258b6abc040597d3abaea2e6c86ffee481ff7afb9b858",
665 ),
666 ];
667 for (tweak, msg, expected) in cases {
668 assert_eq!(hash2n(&cipher.h1, tweak, msg).to_vec(), unhex(expected));
669 }
670 }
671
672 #[test]
673 fn test_kat_r3() {
674 let key: [u8; 16] = core::array::from_fn(|i| i as u8);
675 let cipher = Hctr2pp_128::new(&key);
676
677 let r: [u8; 16] = core::array::from_fn(|i| i as u8);
678 let (u, v) = cipher.r3(&r);
679 assert_eq!(u.to_vec(), unhex("cf53026c002409032271b44d2cfb76ae"));
680 assert_eq!(v.to_vec(), unhex("cc0108efd8d927ec03a148f06bec9c38"));
681 }
682
683 #[test]
684 fn test_kat_encrypt_128() {
685 let key: [u8; 16] = core::array::from_fn(|i| i as u8);
686 let cipher = Hctr2pp_128::new(&key);
687
688 let cases: [(&[u8], &str, &str); 3] = [
689 (
690 b"",
691 "000102030405060708090a0b0c0d0e0f",
692 "02c3c1ea3033a092e21a16acaf88121b",
693 ),
694 (
695 b"tweak",
696 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
697 "46feab9309b3e5826370ad00561963c698a293833efa5ce25c23786df2f4abad",
698 ),
699 (
700 &unhex(
701 "0104070a0d101316191c1f2225282b2e3134373a3d404346494c4f5255585b5e6164676a\
702 6d707376797c7f8285888b8e9194979a9da0a3a6a9acafb2b5b8bbbec1c4c7cacdd0",
703 ),
704 "050c131a21282f363d444b525960676e757c838a91989fa6adb4bbc2c9d0d7dee5ecf3fa\
705 01080f161d242b323940474e55",
706 "8ce2a701bc7547a38212d07087d365b4bf6b4bfe530436ec11f9087b813457a013fcfc18\
707 9b0ca9e172c2a3c148ab621beb",
708 ),
709 ];
710 for (tweak, pt_hex, ct_hex) in cases {
711 let pt = unhex(pt_hex);
712 let expected_ct = unhex(ct_hex);
713 let mut ct = vec![0u8; pt.len()];
714 cipher.encrypt(&pt, tweak, &mut ct).unwrap();
715 assert_eq!(ct, expected_ct);
716
717 let mut decrypted = vec![0u8; ct.len()];
718 cipher.decrypt(&ct, tweak, &mut decrypted).unwrap();
719 assert_eq!(decrypted, pt);
720 }
721 }
722
723 #[test]
724 fn test_kat_encrypt_256() {
725 let key: [u8; 32] = core::array::from_fn(|i| i as u8);
726 let cipher = Hctr2pp_256::new(&key);
727
728 let pt = unhex("03080d12171c21262b30353a3f44494e53585d62676c71767b80858a8f94999ea3");
729 let expected_ct =
730 unhex("d885008594f696577cd7bf4478d27965d8741fd5eda96612e8ef397df08a4d0fec");
731 let mut ct = vec![0u8; pt.len()];
732 cipher.encrypt(&pt, b"tweak 256", &mut ct).unwrap();
733 assert_eq!(ct, expected_ct);
734
735 let mut decrypted = vec![0u8; ct.len()];
736 cipher.decrypt(&ct, b"tweak 256", &mut decrypted).unwrap();
737 assert_eq!(decrypted, pt);
738 }
739
740 #[test]
741 fn test_hctr2pp_128_output_length_mismatch() {
742 let key = [0u8; 16];
743 let cipher = Hctr2pp_128::new(&key);
744
745 let plaintext = [0x42u8; 32];
746 let mut too_short = [0u8; 16];
747 let mut too_long = [0u8; 48];
748
749 assert_eq!(
750 cipher.encrypt(&plaintext, b"", &mut too_short),
751 Err(Error::OutputLengthMismatch)
752 );
753 assert_eq!(
754 cipher.decrypt(&plaintext, b"", &mut too_long),
755 Err(Error::OutputLengthMismatch)
756 );
757 }
758
759 #[test]
760 fn test_hctr2pp_128_long_tweak() {
761 let key = [3u8; 16];
762 let cipher = Hctr2pp_128::new(&key);
763
764 let plaintext = [0x11u8; 40];
765 let tweak = [0x77u8; 100];
766 let mut ciphertext = [0u8; 40];
767 let mut decrypted = [0u8; 40];
768
769 cipher.encrypt(&plaintext, &tweak, &mut ciphertext).unwrap();
770 cipher.decrypt(&ciphertext, &tweak, &mut decrypted).unwrap();
771 assert_eq!(plaintext, decrypted);
772 }
773}