1#![allow(deprecated)]
2#[allow(deprecated)]
21use aes::cipher::{Array, BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
22use aes::{Aes128, Aes256};
23use polyval::{Polyval, universal_hash::UniversalHash};
24
25use crate::common::{BLOCK_LENGTH, Direction, Error, absorb, xctr, xor_blocks, xor_blocks_3};
26use crate::hctr2::AesCipher;
27
28#[allow(non_camel_case_types)]
30#[deprecated(note = "Use common::Error instead")]
31pub type Chctr2Error = Error;
32
33pub struct Chctr2<Aes: AesCipher> {
35 ks1_enc: Aes,
36 ks1_dec: Aes::Dec,
37 h1: [u8; BLOCK_LENGTH],
38 l1: [u8; BLOCK_LENGTH],
39 ks2_enc: Aes,
40 ks2_dec: Aes::Dec,
41 h2: [u8; BLOCK_LENGTH],
42 l2: [u8; BLOCK_LENGTH],
43}
44
45#[allow(non_camel_case_types)]
47pub type Chctr2_128 = Chctr2<Aes128>;
48
49#[allow(non_camel_case_types)]
51pub type Chctr2_256 = Chctr2<Aes256>;
52
53impl<Aes: AesCipher> Chctr2<Aes> {
54 pub const KEY_LENGTH: usize = Aes::KEY_LEN * 2;
56
57 pub const SINGLE_KEY_LENGTH: usize = Aes::KEY_LEN;
59
60 pub const BLOCK_LENGTH: usize = BLOCK_LENGTH;
62
63 pub const MIN_INPUT_LENGTH: usize = BLOCK_LENGTH;
65
66 pub fn new_split(key1: &[u8], key2: &[u8]) -> Self {
68 debug_assert_eq!(key1.len(), Aes::KEY_LEN);
69 debug_assert_eq!(key2.len(), Aes::KEY_LEN);
70
71 fn derive_hl<A: BlockCipherEncrypt>(ks: &A) -> ([u8; 16], [u8; 16]) {
72 let mut h_block = Array::clone_from_slice(&[0u8; 16]);
73 let mut l_block = Array::clone_from_slice(&{
74 let mut b = [0u8; 16];
75 b[0] = 1;
76 b
77 });
78 ks.encrypt_block(&mut h_block);
79 ks.encrypt_block(&mut l_block);
80 (
81 h_block.as_slice().try_into().unwrap(),
82 l_block.as_slice().try_into().unwrap(),
83 )
84 }
85
86 let ks1_enc = Aes::new(Array::from_slice(key1));
87 let ks1_dec = Aes::new_dec(key1);
88 let (h1, l1) = derive_hl(&ks1_enc);
89
90 let ks2_enc = Aes::new(Array::from_slice(key2));
91 let ks2_dec = Aes::new_dec(key2);
92 let (h2, l2) = derive_hl(&ks2_enc);
93
94 Self {
95 ks1_enc,
96 ks1_dec,
97 h1,
98 l1,
99 ks2_enc,
100 ks2_dec,
101 h2,
102 l2,
103 }
104 }
105
106 pub fn encrypt(
108 &self,
109 plaintext: &[u8],
110 tweak: &[u8],
111 ciphertext: &mut [u8],
112 ) -> Result<(), Error> {
113 self.chctr2(plaintext, tweak, ciphertext, Direction::Encrypt)
114 }
115
116 pub fn decrypt(
118 &self,
119 ciphertext: &[u8],
120 tweak: &[u8],
121 plaintext: &mut [u8],
122 ) -> Result<(), Error> {
123 self.chctr2(ciphertext, tweak, plaintext, Direction::Decrypt)
124 }
125
126 fn chctr2(
129 &self,
130 src: &[u8],
131 tweak: &[u8],
132 dst: &mut [u8],
133 direction: Direction,
134 ) -> Result<(), Error> {
135 debug_assert_eq!(dst.len(), src.len());
136 if src.len() < BLOCK_LENGTH {
137 return Err(Error::InputTooShort);
138 }
139
140 let m0: [u8; BLOCK_LENGTH] = src[..BLOCK_LENGTH].try_into().unwrap();
141 let m_star = &src[BLOCK_LENGTH..];
142
143 let tweak_len_bits = tweak.len() * 8;
144 let tweak_len_encoded: u128 = if m_star.len() % BLOCK_LENGTH == 0 {
145 (2 * tweak_len_bits + 2) as u128
146 } else {
147 (2 * tweak_len_bits + 3) as u128
148 };
149 let len_block = Array::from(tweak_len_encoded.to_le_bytes());
150
151 let mut poly1 = Polyval::new(Array::from_slice(&self.h1));
152 poly1.update(&[len_block]);
153 poly1.update_padded(tweak);
154 let poly1_after_tweak = poly1.clone();
155
156 let mut poly2 = Polyval::new(Array::from_slice(&self.h2));
157 poly2.update(&[len_block]);
158 poly2.update_padded(tweak);
159 let poly2_after_tweak = poly2.clone();
160
161 match direction {
162 Direction::Encrypt => {
163 let z1 = absorb(&mut poly1, m_star);
164 let x1_0 = xor_blocks(&z1, &m0);
165
166 let y1_0: [u8; 16] = {
167 let mut block = Array::clone_from_slice(&x1_0);
168 self.ks1_enc.encrypt_block(&mut block);
169 block.as_slice().try_into().unwrap()
170 };
171
172 let iv1 = xor_blocks_3(&x1_0, &y1_0, &self.l1);
173
174 let (_, r_slice) = dst.split_at_mut(BLOCK_LENGTH);
175 xctr(&self.ks1_enc, r_slice, m_star, &iv1);
176
177 let mut poly1 = poly1_after_tweak.clone();
178 let mut poly2 = poly2_after_tweak.clone();
179 let h1_r = absorb(&mut poly1, r_slice);
180 let h2_r = absorb(&mut poly2, r_slice);
181 let z1_2 = xor_blocks(&h1_r, &h2_r);
182
183 let x2_0 = xor_blocks(&y1_0, &z1_2);
184
185 let y2_0: [u8; 16] = {
186 let mut block = Array::clone_from_slice(&x2_0);
187 self.ks2_enc.encrypt_block(&mut block);
188 block.as_slice().try_into().unwrap()
189 };
190
191 let iv2 = xor_blocks_3(&x2_0, &y2_0, &self.l2);
192
193 let c_star_src: Vec<u8> = r_slice.to_vec();
194 let (_, c_star) = dst.split_at_mut(BLOCK_LENGTH);
195 xctr(&self.ks2_enc, c_star, &c_star_src, &iv2);
196
197 let mut poly2 = poly2_after_tweak;
198 let z2 = absorb(&mut poly2, c_star);
199 dst[..BLOCK_LENGTH].copy_from_slice(&xor_blocks(&y2_0, &z2));
200 }
201 Direction::Decrypt => {
202 let c0: [u8; BLOCK_LENGTH] = src[..BLOCK_LENGTH].try_into().unwrap();
203 let c_star = &src[BLOCK_LENGTH..];
204
205 let z2 = absorb(&mut poly2, c_star);
206 let y2_0 = xor_blocks(&c0, &z2);
207
208 let x2_0: [u8; 16] = {
209 let mut block = Array::clone_from_slice(&y2_0);
210 self.ks2_dec.decrypt_block(&mut block);
211 block.as_slice().try_into().unwrap()
212 };
213
214 let iv2 = xor_blocks_3(&x2_0, &y2_0, &self.l2);
215
216 let (_, r_slice) = dst.split_at_mut(BLOCK_LENGTH);
217 xctr(&self.ks2_enc, r_slice, c_star, &iv2);
218
219 let mut poly1 = poly1_after_tweak.clone();
220 let mut poly2 = poly2_after_tweak.clone();
221 let h1_r = absorb(&mut poly1, r_slice);
222 let h2_r = absorb(&mut poly2, r_slice);
223 let z1_2 = xor_blocks(&h1_r, &h2_r);
224
225 let y1_0 = xor_blocks(&x2_0, &z1_2);
226
227 let x1_0: [u8; 16] = {
228 let mut block = Array::clone_from_slice(&y1_0);
229 self.ks1_dec.decrypt_block(&mut block);
230 block.as_slice().try_into().unwrap()
231 };
232
233 let iv1 = xor_blocks_3(&x1_0, &y1_0, &self.l1);
234
235 let r_copy: Vec<u8> = r_slice.to_vec();
236 let (_, m_star_out) = dst.split_at_mut(BLOCK_LENGTH);
237 xctr(&self.ks1_enc, m_star_out, &r_copy, &iv1);
238
239 let mut poly1 = poly1_after_tweak;
240 let z1 = absorb(&mut poly1, m_star_out);
241 dst[..BLOCK_LENGTH].copy_from_slice(&xor_blocks(&x1_0, &z1));
242 }
243 }
244
245 Ok(())
246 }
247}
248
249impl Chctr2_128 {
250 pub fn new(key: &[u8; 32]) -> Self {
252 let key1: [u8; 16] = key[..16].try_into().unwrap();
253 let key2: [u8; 16] = key[16..].try_into().unwrap();
254 Self::new_split(&key1, &key2)
255 }
256}
257
258impl Chctr2_256 {
259 pub fn new(key: &[u8; 64]) -> Self {
261 let key1: [u8; 32] = key[..32].try_into().unwrap();
262 let key2: [u8; 32] = key[32..].try_into().unwrap();
263 Self::new_split(&key1, &key2)
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 #[test]
272 fn test_chctr2_128_roundtrip() {
273 let key = [0u8; 32];
274 let cipher = Chctr2_128::new(&key);
275
276 let plaintext = b"Hello, CHCTR2 World!";
277 let mut ciphertext = vec![0u8; plaintext.len()];
278 let mut decrypted = vec![0u8; plaintext.len()];
279
280 let tweak = b"test tweak";
281
282 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
283 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
284
285 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
286 }
287
288 #[test]
289 fn test_chctr2_128_roundtrip_nonzero_key() {
290 let key: [u8; 32] = core::array::from_fn(|i| (i + 1) as u8);
291 let cipher = Chctr2_128::new(&key);
292
293 let plaintext = b"Hello, CHCTR2 World!";
294 let mut ciphertext = vec![0u8; plaintext.len()];
295 let mut decrypted = vec![0u8; plaintext.len()];
296
297 let tweak = b"test tweak";
298
299 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
300 assert_ne!(plaintext.as_slice(), ciphertext.as_slice());
301
302 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
303 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
304 }
305
306 #[test]
307 fn test_chctr2_128_minimum_length() {
308 let key = [0u8; 32];
309 let cipher = Chctr2_128::new(&key);
310
311 let plaintext = [0x42u8; 16];
312 let mut ciphertext = [0u8; 16];
313 let mut decrypted = [0u8; 16];
314
315 cipher.encrypt(&plaintext, b"", &mut ciphertext).unwrap();
316 cipher.decrypt(&ciphertext, b"", &mut decrypted).unwrap();
317
318 assert_eq!(plaintext, decrypted);
319 }
320
321 #[test]
322 fn test_chctr2_128_input_too_short() {
323 let key = [0u8; 32];
324 let cipher = Chctr2_128::new(&key);
325
326 let plaintext = [0x42u8; 15];
327 let mut ciphertext = [0u8; 15];
328
329 assert_eq!(
330 cipher.encrypt(&plaintext, b"", &mut ciphertext),
331 Err(Error::InputTooShort)
332 );
333 }
334
335 #[test]
336 fn test_chctr2_128_different_tweaks() {
337 let key = [0u8; 32];
338 let cipher = Chctr2_128::new(&key);
339
340 let plaintext = [0x42u8; 32];
341 let mut ciphertext1 = [0u8; 32];
342 let mut ciphertext2 = [0u8; 32];
343
344 cipher
345 .encrypt(&plaintext, b"tweak1", &mut ciphertext1)
346 .unwrap();
347 cipher
348 .encrypt(&plaintext, b"tweak2", &mut ciphertext2)
349 .unwrap();
350
351 assert_ne!(ciphertext1, ciphertext2);
352 }
353
354 #[test]
355 fn test_chctr2_128_split_init() {
356 let key1 = [0x01u8; 16];
357 let key2 = [0x02u8; 16];
358 let cipher = Chctr2_128::new_split(&key1, &key2);
359
360 let plaintext = b"Test split key init";
361 let mut ciphertext = vec![0u8; plaintext.len()];
362 let mut decrypted = vec![0u8; plaintext.len()];
363
364 cipher
365 .encrypt(plaintext, b"tweak", &mut ciphertext)
366 .unwrap();
367 cipher
368 .decrypt(&ciphertext, b"tweak", &mut decrypted)
369 .unwrap();
370
371 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
372 }
373
374 #[test]
375 fn test_chctr2_128_large_message() {
376 let key = [0u8; 32];
377 let cipher = Chctr2_128::new(&key);
378
379 let plaintext = [0xABu8; 1024];
380 let mut ciphertext = [0u8; 1024];
381 let mut decrypted = [0u8; 1024];
382
383 cipher
384 .encrypt(&plaintext, b"large tweak", &mut ciphertext)
385 .unwrap();
386 cipher
387 .decrypt(&ciphertext, b"large tweak", &mut decrypted)
388 .unwrap();
389
390 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
391 }
392
393 #[test]
394 fn test_chctr2_256_roundtrip() {
395 let key = [0u8; 64];
396 let cipher = Chctr2_256::new(&key);
397
398 let plaintext = b"Hello, CHCTR2-256 World!";
399 let mut ciphertext = vec![0u8; plaintext.len()];
400 let mut decrypted = vec![0u8; plaintext.len()];
401
402 let tweak = b"test tweak 256";
403
404 cipher.encrypt(plaintext, tweak, &mut ciphertext).unwrap();
405 cipher.decrypt(&ciphertext, tweak, &mut decrypted).unwrap();
406
407 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
408 }
409}