1#![allow(deprecated)]
2#[allow(deprecated)]
19use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
20use aes::{Aes128, Aes256};
21use polyval::{Polyval, universal_hash::UniversalHash};
22
23use crate::common::{BLOCK_LENGTH, Direction, Error, absorb, xctr, xor_blocks, xor_blocks_3};
24
25pub trait AesCipher: BlockCipherEncrypt + KeyInit + Clone {
27 type Dec: BlockCipherDecrypt + KeyInit;
28 const KEY_LEN: usize;
29
30 fn new_dec(key: &[u8]) -> Self::Dec;
31}
32
33impl AesCipher for Aes128 {
34 type Dec = aes::Aes128Dec;
35 const KEY_LEN: usize = 16;
36
37 fn new_dec(key: &[u8]) -> Self::Dec {
38 aes::Aes128Dec::new(Array::from_slice(key))
39 }
40}
41
42impl AesCipher for Aes256 {
43 type Dec = aes::Aes256Dec;
44 const KEY_LEN: usize = 32;
45
46 fn new_dec(key: &[u8]) -> Self::Dec {
47 aes::Aes256Dec::new(Array::from_slice(key))
48 }
49}
50
51pub struct Hctr2<Aes: AesCipher> {
53 ks_enc: Aes,
54 ks_dec: Aes::Dec,
55 h: [u8; BLOCK_LENGTH],
56 l: [u8; BLOCK_LENGTH],
57}
58
59#[allow(non_camel_case_types)]
61pub type Hctr2_128 = Hctr2<Aes128>;
62
63#[allow(non_camel_case_types)]
65pub type Hctr2_256 = Hctr2<Aes256>;
66
67#[allow(non_camel_case_types)]
69#[deprecated(note = "Use common::Error instead")]
70pub type Hctr2Error = Error;
71
72impl<Aes: AesCipher> Hctr2<Aes> {
73 pub const KEY_LENGTH: usize = Aes::KEY_LEN;
75
76 pub const BLOCK_LENGTH: usize = BLOCK_LENGTH;
78
79 pub const MIN_INPUT_LENGTH: usize = BLOCK_LENGTH;
81
82 pub fn new(key: &[u8]) -> Self {
84 debug_assert_eq!(key.len(), Aes::KEY_LEN);
85
86 let ks_enc = Aes::new(Array::from_slice(key));
87 let ks_dec = Aes::new_dec(key);
88
89 let mut block0 = Array::clone_from_slice(&[0u8; 16]);
90 let mut block1 = Array::clone_from_slice(&{
91 let mut b = [0u8; 16];
92 b[0] = 1;
93 b
94 });
95
96 ks_enc.encrypt_block(&mut block0);
97 ks_enc.encrypt_block(&mut block1);
98
99 let h: [u8; 16] = block0.as_slice().try_into().unwrap();
100 let l: [u8; 16] = block1.as_slice().try_into().unwrap();
101 Self {
102 ks_enc,
103 ks_dec,
104 h,
105 l,
106 }
107 }
108
109 pub fn encrypt(
119 &self,
120 plaintext: &[u8],
121 tweak: &[u8],
122 ciphertext: &mut [u8],
123 ) -> Result<(), Error> {
124 self.hctr2(plaintext, tweak, ciphertext, Direction::Encrypt)
125 }
126
127 pub fn decrypt(
137 &self,
138 ciphertext: &[u8],
139 tweak: &[u8],
140 plaintext: &mut [u8],
141 ) -> Result<(), Error> {
142 self.hctr2(ciphertext, tweak, plaintext, Direction::Decrypt)
143 }
144
145 fn hctr2(
146 &self,
147 src: &[u8],
148 tweak: &[u8],
149 dst: &mut [u8],
150 direction: Direction,
151 ) -> Result<(), Error> {
152 debug_assert_eq!(dst.len(), src.len());
153 if src.len() < BLOCK_LENGTH {
154 return Err(Error::InputTooShort);
155 }
156
157 let m: [u8; BLOCK_LENGTH] = src[..BLOCK_LENGTH].try_into().unwrap();
158 let n = &src[BLOCK_LENGTH..];
159
160 let tweak_len_bits = tweak.len() * 8;
161 let tweak_len_encoded: u128 = if n.len() % BLOCK_LENGTH == 0 {
162 (2 * tweak_len_bits + 2) as u128
163 } else {
164 (2 * tweak_len_bits + 3) as u128
165 };
166
167 let mut poly = Polyval::new(Array::from_slice(&self.h));
168 poly.update(&[Array::from(tweak_len_encoded.to_le_bytes())]);
169 poly.update_padded(tweak);
170 let poly_after_tweak = poly.clone();
171
172 let hh = absorb(&mut poly, n);
173 let mm = xor_blocks(&hh, &m);
174
175 let uu: [u8; BLOCK_LENGTH] = match direction {
176 Direction::Encrypt => {
177 let mut block = Array::clone_from_slice(&mm);
178 self.ks_enc.encrypt_block(&mut block);
179 block.as_slice().try_into().unwrap()
180 }
181 Direction::Decrypt => {
182 let mut block = Array::clone_from_slice(&mm);
183 self.ks_dec.decrypt_block(&mut block);
184 block.as_slice().try_into().unwrap()
185 }
186 };
187
188 let s = xor_blocks_3(&mm, &uu, &self.l);
189 let (u, v) = dst.split_at_mut(BLOCK_LENGTH);
190 xctr(&self.ks_enc, v, n, &s);
191
192 let mut poly = poly_after_tweak;
193 let hh2 = absorb(&mut poly, v);
194 u.copy_from_slice(&xor_blocks(&uu, &hh2));
195
196 Ok(())
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_hctr2_128_roundtrip() {
206 let key = [0u8; 16];
207 let cipher = Hctr2_128::new(&key);
208
209 let plaintext = b"Hello, HCTR2 World!";
210 let mut ciphertext = vec![0u8; plaintext.len()];
211 let mut decrypted = vec![0u8; plaintext.len()];
212
213 let tweak = b"test tweak";
214
215 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
216 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
217
218 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
219 }
220
221 #[test]
222 fn test_hctr2_128_roundtrip_nonzero_key() {
223 let key = [
224 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
225 0x0f, 0x10,
226 ];
227 let cipher = Hctr2_128::new(&key);
228
229 let plaintext = b"Hello, HCTR2 World!";
230 let mut ciphertext = vec![0u8; plaintext.len()];
231 let mut decrypted = vec![0u8; plaintext.len()];
232
233 let tweak = b"test tweak";
234
235 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
236 assert_ne!(plaintext.as_slice(), ciphertext.as_slice());
237
238 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
239
240 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
241 }
242
243 #[test]
244 fn test_hctr2_128_minimum_length() {
245 let key = [0u8; 16];
246 let cipher = Hctr2_128::new(&key);
247
248 let plaintext = [0x42u8; 16];
249 let mut ciphertext = [0u8; 16];
250 let mut decrypted = [0u8; 16];
251
252 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
253 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
254
255 assert_eq!(plaintext, decrypted);
256 }
257
258 #[test]
259 fn test_hctr2_128_input_too_short() {
260 let key = [0u8; 16];
261 let cipher = Hctr2_128::new(&key);
262
263 let plaintext = [0x42u8; 15]; let mut ciphertext = [0u8; 15];
265
266 assert_eq!(
267 cipher.encrypt(&plaintext, b"", &mut ciphertext),
268 Err(Error::InputTooShort)
269 );
270 }
271
272 #[test]
273 fn test_hctr2_128_different_tweaks() {
274 let key = [0u8; 16];
275 let cipher = Hctr2_128::new(&key);
276
277 let plaintext = [0x42u8; 32];
278 let mut ciphertext1 = [0u8; 32];
279 let mut ciphertext2 = [0u8; 32];
280
281 cipher
282 .encrypt(&plaintext, b"tweak1", &mut ciphertext1)
283 .unwrap();
284 cipher
285 .encrypt(&plaintext, b"tweak2", &mut ciphertext2)
286 .unwrap();
287 assert_ne!(ciphertext1, ciphertext2);
288 }
289
290 #[test]
291 fn test_hctr2_128_large_message() {
292 let key = [0u8; 16];
293 let cipher = Hctr2_128::new(&key);
294
295 let plaintext = [0xABu8; 1024];
296 let mut ciphertext = [0u8; 1024];
297 let mut decrypted = [0u8; 1024];
298
299 cipher
300 .encrypt(&plaintext, b"large tweak", &mut ciphertext)
301 .unwrap();
302 cipher
303 .decrypt(&ciphertext, b"large tweak", &mut decrypted)
304 .unwrap();
305
306 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
307 }
308
309 #[test]
310 fn test_hctr2_256_roundtrip() {
311 let key = [0u8; 32];
312 let cipher = Hctr2_256::new(&key);
313
314 let plaintext = b"Hello, HCTR2-256 World!";
315 let mut ciphertext = vec![0u8; plaintext.len()];
316 let mut decrypted = vec![0u8; plaintext.len()];
317
318 let tweak = b"test tweak 256";
319
320 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
321 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
322
323 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
324 }
325}