]> git.proxmox.com Git - rustc.git/blame - vendor/c2-chacha/src/rustcrypto_impl.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / vendor / c2-chacha / src / rustcrypto_impl.rs
CommitLineData
416331ca
XL
1use byteorder::{ByteOrder, LE};
2use core::cmp;
3use crate::guts::generic_array::typenum::{Unsigned, U10, U12, U24, U32, U4, U6, U8};
4use crate::guts::generic_array::{ArrayLength, GenericArray};
5use crate::guts::{ChaCha, Machine, BLOCK, BLOCK64, BUFSZ};
6pub use stream_cipher;
7use stream_cipher::{LoopError, NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
8
9const BIG_LEN: u64 = 0;
10const SMALL_LEN: u64 = 1 << 32;
11
12#[derive(Clone)]
13pub struct Buffer {
14 pub state: ChaCha,
15 pub out: [u8; BLOCK],
16 pub have: i8,
17 pub len: u64,
18 pub fresh: bool,
19}
20
21#[derive(Default)]
22pub struct X;
23#[derive(Default)]
24pub struct O;
25#[derive(Clone)]
26pub struct ChaChaAny<NonceSize, Rounds, IsX> {
27 pub state: Buffer,
28 pub _nonce_size: NonceSize,
29 pub _rounds: Rounds,
30 pub _is_x: IsX,
31}
32
33impl Buffer {
34 fn try_apply_keystream<EnableWide: AsBool>(
35 &mut self,
36 mut data: &mut [u8],
37 drounds: u32,
38 ) -> Result<(), ()> {
39 // Lazy fill: after a seek() we may be partway into a block we don't have yet.
40 // We can do this before the overflow check because this is not an effect of the current
41 // operation.
42 if self.have < 0 {
43 self.state.refill(drounds, &mut self.out);
44 self.have += BLOCK as i8;
45 // checked in seek()
46 self.len -= 1;
47 }
48 let mut have = self.have as usize;
49 let have_ready = cmp::min(have, data.len());
50 // Check if the requested position would wrap the block counter. Use self.fresh as an extra
51 // bit to distinguish the initial state from the valid state with no blocks left.
52 let datalen = (data.len() - have_ready) as u64;
53 let blocks_needed = datalen / BLOCK64 + u64::from(datalen % BLOCK64 != 0);
54 let (l, o) = self.len.overflowing_sub(blocks_needed);
55 if o && !self.fresh {
56 return Err(());
57 }
58 self.len = l;
59 self.fresh &= blocks_needed == 0;
60 // If we have data in the buffer, use that first.
61 let (d0, d1) = data.split_at_mut(have_ready);
62 for (data_b, key_b) in d0.iter_mut().zip(&self.out[(BLOCK - have)..]) {
63 *data_b ^= *key_b;
64 }
65 data = d1;
66 have -= have_ready;
67 // Process wide chunks.
68 if EnableWide::BOOL {
69 let (d0, d1) = data.split_at_mut(data.len() & !(BUFSZ - 1));
70 for dd in d0.chunks_exact_mut(BUFSZ) {
71 let mut buf = [0; BUFSZ];
72 self.state.refill4(drounds, &mut buf);
73 for (data_b, key_b) in dd.iter_mut().zip(buf.iter()) {
74 *data_b ^= *key_b;
75 }
76 }
77 data = d1;
78 }
79 // Handle the tail a block at a time so we'll have storage for any leftovers.
80 for dd in data.chunks_mut(BLOCK) {
81 self.state.refill(drounds, &mut self.out);
82 for (data_b, key_b) in dd.iter_mut().zip(self.out.iter()) {
83 *data_b ^= *key_b;
84 }
85 have = BLOCK - dd.len();
86 }
87 self.have = have as i8;
88 Ok(())
89 }
90}
91
92dispatch_light128!(m, Mach, {
93 fn seek64(buf: &mut Buffer, ct: u64) {
94 let blockct = ct / BLOCK64;
95 buf.len = BIG_LEN.wrapping_sub(blockct);
96 buf.fresh = blockct == 0;
97 buf.have = -((ct % BLOCK64) as i8);
98 buf.state.seek64(m, blockct);
99 }
100});
101
102dispatch_light128!(m, Mach, {
103 fn seek32(buf: &mut Buffer, ct: u64) {
104 let blockct = ct / BLOCK64;
105 assert!(blockct < SMALL_LEN || (blockct == SMALL_LEN && ct % BLOCK64 == 0));
106 buf.len = SMALL_LEN - blockct;
107 buf.have = -((ct % BLOCK64) as i8);
108 buf.state.seek32(m, blockct as u32);
109 }
110});
111
112#[cfg(test)]
113impl<NonceSize, Rounds: Unsigned, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
114 pub fn try_apply_keystream_narrow(&mut self, data: &mut [u8]) -> Result<(), ()> {
115 self.state
116 .try_apply_keystream::<WideDisabled>(data, Rounds::U32)
117 }
118}
119
120impl<NonceSize, Rounds> ChaChaAny<NonceSize, Rounds, O>
121where
122 NonceSize: Unsigned + ArrayLength<u8> + Default,
123 Rounds: Default,
124{
125 #[inline]
126 fn new(key: &GenericArray<u8, U32>, nonce: &GenericArray<u8, NonceSize>) -> Self {
127 let nonce_len = nonce.len();
128 ChaChaAny {
129 state: Buffer {
130 state: init_chacha(key, nonce),
131 out: [0; BLOCK],
132 have: 0,
133 len: if nonce_len == 12 { SMALL_LEN } else { BIG_LEN },
134 fresh: nonce_len != 12,
135 },
136 _nonce_size: Default::default(),
137 _rounds: Default::default(),
138 _is_x: Default::default(),
139 }
140 }
141}
142
143impl<Rounds: Unsigned + Default> ChaChaAny<U24, Rounds, X> {
144 fn new(key: &GenericArray<u8, U32>, nonce: &GenericArray<u8, U24>) -> Self {
145 ChaChaAny {
146 state: Buffer {
147 state: init_chacha_x(key, nonce, Rounds::U32),
148 out: [0; BLOCK],
149 have: 0,
150 len: BIG_LEN,
151 fresh: true,
152 },
153 _nonce_size: Default::default(),
154 _rounds: Default::default(),
155 _is_x: Default::default(),
156 }
157 }
158}
159
160impl<NonceSize: Unsigned, Rounds, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
161 #[inline(always)]
162 fn seek(&mut self, ct: u64) {
163 if NonceSize::U32 != 12 {
164 seek64(&mut self.state, ct);
165 } else {
166 seek32(&mut self.state, ct);
167 }
168 }
169}
170
171impl<NonceSize, Rounds: Unsigned, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
172 #[inline]
173 fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), ()> {
174 self.state
175 .try_apply_keystream::<WideEnabled>(data, Rounds::U32)
176 }
177}
178
179impl<NonceSize, Rounds> NewStreamCipher for ChaChaAny<NonceSize, Rounds, O>
180where
181 NonceSize: Unsigned + ArrayLength<u8> + Default,
182 Rounds: Default,
183{
184 type KeySize = U32;
185 type NonceSize = NonceSize;
186 #[inline]
187 fn new(
188 key: &GenericArray<u8, Self::KeySize>,
189 nonce: &GenericArray<u8, Self::NonceSize>,
190 ) -> Self {
191 Self::new(key, nonce)
192 }
193}
194
195impl<Rounds: Unsigned + Default> NewStreamCipher for ChaChaAny<U24, Rounds, X> {
196 type KeySize = U32;
197 type NonceSize = U24;
198 #[inline]
199 fn new(
200 key: &GenericArray<u8, Self::KeySize>,
201 nonce: &GenericArray<u8, Self::NonceSize>,
202 ) -> Self {
203 Self::new(key, nonce)
204 }
205}
206
207impl<NonceSize: Unsigned, Rounds, IsX> SyncStreamCipherSeek for ChaChaAny<NonceSize, Rounds, IsX> {
208 #[inline]
209 fn current_pos(&self) -> u64 {
210 unimplemented!()
211 }
212 #[inline(always)]
213 fn seek(&mut self, ct: u64) {
214 Self::seek(self, ct)
215 }
216}
217
218impl<NonceSize, Rounds: Unsigned, IsX> SyncStreamCipher for ChaChaAny<NonceSize, Rounds, IsX> {
219 #[inline]
220 fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError> {
221 Self::try_apply_keystream(self, data).map_err(|_| LoopError)
222 }
223}
224
225trait AsBool {
226 const BOOL: bool;
227}
228struct WideEnabled;
229impl AsBool for WideEnabled {
230 const BOOL: bool = true;
231}
232#[cfg(test)]
233struct WideDisabled;
234#[cfg(test)]
235impl AsBool for WideDisabled {
236 const BOOL: bool = false;
237}
238
239dispatch_light128!(m, Mach, {
240 fn init_chacha(key: &GenericArray<u8, U32>, nonce: &[u8]) -> ChaCha {
241 let ctr_nonce = [
242 0,
243 if nonce.len() == 12 {
244 LE::read_u32(&nonce[0..4])
245 } else {
246 0
247 },
248 LE::read_u32(&nonce[nonce.len() - 8..nonce.len() - 4]),
249 LE::read_u32(&nonce[nonce.len() - 4..]),
250 ];
251 let key0: Mach::u32x4 = m.read_le(&key[..16]);
252 let key1: Mach::u32x4 = m.read_le(&key[16..]);
253 ChaCha {
254 b: key0.into(),
255 c: key1.into(),
256 d: ctr_nonce.into(),
257 }
258 }
259});
260
261dispatch_light128!(m, Mach, {
262 fn init_chacha_x(
263 key: &GenericArray<u8, U32>,
264 nonce: &GenericArray<u8, U24>,
265 rounds: u32,
266 ) -> ChaCha {
267 let key0: Mach::u32x4 = m.read_le(&key[..16]);
268 let key1: Mach::u32x4 = m.read_le(&key[16..]);
269 let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
270 let mut state = ChaCha {
271 b: key0.into(),
272 c: key1.into(),
273 d: nonce0.into(),
274 };
275 let x = state.refill_rounds(rounds);
276 let ctr_nonce1 = [
277 0,
278 0,
279 LE::read_u32(&nonce[16..20]),
280 LE::read_u32(&nonce[20..24]),
281 ];
282 state.b = x.a;
283 state.c = x.d;
284 state.d = ctr_nonce1.into();
285 state
286 }
287});
288
289/// IETF RFC 7539 ChaCha. Unsuitable for messages longer than 256 GiB.
290pub type Ietf = ChaChaAny<U12, U10, O>;
291/// ChaCha20, as used in several standards; from Bernstein's original publication.
292pub type ChaCha20 = ChaChaAny<U8, U10, O>;
293/// Similar to ChaCha20, but with fewer rounds for higher performance.
294pub type ChaCha12 = ChaChaAny<U8, U6, O>;
295/// Similar to ChaCha20, but with fewer rounds for higher performance.
296pub type ChaCha8 = ChaChaAny<U8, U4, O>;
297/// Constructed analogously to XSalsa20; mixes during initialization to support both a long nonce
298/// and a full-length (64-bit) block counter.
299pub type XChaCha20 = ChaChaAny<U24, U10, X>;
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 #[test]
306 fn chacha20_case_1() {
307 let key = hex!("fa44478c59ca70538e3549096ce8b523232c50d9e8e8d10c203ef6c8d07098a5");
308 let nonce = hex!("8d3a0d6d7827c007");
309 let expected = hex!("
310 1546a547ff77c5c964e44fd039e913c6395c8f19d43efaa880750f6687b4e6e2d8f42f63546da2d133b5aa2f1ef3f218b6c72943089e4012
311 210c2cbed0e8e93498a6825fc8ff7a504f26db33b6cbe36299436244c9b2eff88302c55933911b7d5dea75f2b6d4761ba44bb6f814c9879d
312 2ba2ac8b178fa1104a368694872339738ffb960e33db39efb8eaef885b910eea078e7a1feb3f8185dafd1455b704d76da3a0ce4760741841
313 217bba1e4ece760eaf68617133431feb806c061173af6b8b2a23be90c5d145cc258e3c119aab2800f0c7bc1959dae75481712cab731b7dfd
314 783fa3a228f9968aaea68f36a92f43c9b523337a55b97bcaf5f5774447bf41e8");
315 let mut state = ChaCha20::new(
316 GenericArray::from_slice(&key),
317 GenericArray::from_slice(&nonce),
318 );
319 let offset = 0x3fffffff70u64;
320 assert!((offset >> 38) != ((offset + 240) >> 38)); // This will overflow the small word of the counter
321 state.seek(offset);
322 let mut result = [0; 256];
323 state.apply_keystream(&mut result);
324 assert_eq!(&expected[..], &result[..]);
325 }
326
327 #[test]
328 fn chacha12_case_1() {
329 let key = hex!("27fc120b013b829f1faeefd1ab417e8662f43e0d73f98de866e346353180fdb7");
330 let nonce = hex!("db4b4a41d8df18aa");
331 let expected = hex!("
332 5f3c8c190a78ab7fe808cae9cbcb0a9837c893492d963a1c2eda6c1558b02c83fc02a44cbbb7e6204d51d1c2430e9c0b58f2937bf593840c
333 850bda9051a1f051ddf09d2a03ebf09f01bdba9da0b6da791b2e645641047d11ebf85087d4de5c015fddd044");
334 let mut state = ChaCha12::new(
335 GenericArray::from_slice(&key),
336 GenericArray::from_slice(&nonce),
337 );
338 let mut result = [0u8; 100];
339 state.apply_keystream(&mut result);
340 assert_eq!(&expected[..], &result[..]);
341 }
342
343 #[test]
344 fn chacha8_case_1() {
345 let key = hex!("641aeaeb08036b617a42cf14e8c5d2d115f8d7cb6ea5e28b9bfaf83e038426a7");
346 let nonce = hex!("a14a1168271d459b");
347 let mut state = ChaCha8::new(
348 GenericArray::from_slice(&key),
349 GenericArray::from_slice(&nonce),
350 );
351 let expected = hex!(
352 "1721c044a8a6453522dddb3143d0be3512633ca3c79bf8ccc3594cb2c2f310f7bd544f55ce0db38123412d6c45207d5cf9af0c6c680cce1f
353 7e43388d1b0346b7133c59fd6af4a5a568aa334ccdc38af5ace201df84d0a3ca225494ca6209345fcf30132e");
354 let mut result = [0u8; 100];
355 state.apply_keystream(&mut result);
356 assert_eq!(&expected[..], &result[..]);
357 }
358
359 #[test]
360 fn test_ietf() {
361 let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
362 let nonce = hex!("000000090000004a00000000");
363 let expected = hex!(
364 "
365 10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
366 d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
367 );
368 let mut state = Ietf::new(
369 GenericArray::from_slice(&key),
370 GenericArray::from_slice(&nonce),
371 );
372 let mut result = [0; 64];
373 state.seek(64);
374 state.apply_keystream(&mut result);
375 assert_eq!(&expected[..], &result[..]);
376 }
377
378 #[test]
379 fn rfc_7539_case_1() {
380 let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
381 let nonce = hex!("000000090000004a00000000");
382 let mut state = Ietf::new(
383 GenericArray::from_slice(&key),
384 GenericArray::from_slice(&nonce),
385 );
386 let mut result = [0; 128];
387 state.apply_keystream(&mut result);
388 let expected = hex!(
389 "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
390 d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
391 );
392 assert_eq!(&expected[..], &result[64..]);
393 }
394
395 #[test]
396 fn rfc_7539_case_2() {
397 let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
398 let nonce = hex!("000000000000004a00000000");
399 let mut state = Ietf::new(
400 GenericArray::from_slice(&key),
401 GenericArray::from_slice(&nonce),
402 );
403 let plaintext = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
404 let mut buf = [0u8; 178];
405 buf[64..].copy_from_slice(plaintext);
406 state.apply_keystream(&mut buf);
407 let expected = hex!("
408 6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab
409 8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42
410 874d");
411 assert_eq!(&expected[..], &buf[64..]);
412 }
413
414 #[test]
415 fn rfc_7539_case_2_chunked() {
416 let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
417 let nonce = hex!("000000000000004a00000000");
418 let mut state = Ietf::new(
419 GenericArray::from_slice(&key),
420 GenericArray::from_slice(&nonce),
421 );
422 let plaintext = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
423 let mut buf = [0u8; 178];
424 buf[64..].copy_from_slice(plaintext);
425 state.apply_keystream(&mut buf[..40]);
426 state.apply_keystream(&mut buf[40..78]);
427 state.apply_keystream(&mut buf[78..79]);
428 state.apply_keystream(&mut buf[79..128]);
429 state.apply_keystream(&mut buf[128..]);
430 let expected = hex!("
431 6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab
432 8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42
433 874d");
434 assert_eq!(&expected[..], &buf[64..]);
435 }
436
437 #[test]
438 fn xchacha20_case_1() {
439 let key = hex!("82f411a074f656c66e7dbddb0a2c1b22760b9b2105f4ffdbb1d4b1e824e21def");
440 let nonce = hex!("3b07ca6e729eb44a510b7a1be51847838a804f8b106b38bd");
441 let mut state = XChaCha20::new(
442 GenericArray::from_slice(&key),
443 GenericArray::from_slice(&nonce),
444 );
445 let mut xs = [0u8; 100];
446 state.apply_keystream(&mut xs);
447 let expected = hex!("
448 201863970b8e081f4122addfdf32f6c03e48d9bc4e34a59654f49248b9be59d3eaa106ac3376e7e7d9d1251f2cbf61ef27000f3d19afb76b
449 9c247151e7bc26467583f520518eccd2055ccd6cc8a195953d82a10c2065916778db35da2be44415d2f5efb0");
450 assert_eq!(&expected[..], &xs[..]);
451 }
452
453 #[test]
454 fn seek_off_end() {
455 let mut st = Ietf::new(
456 GenericArray::from_slice(&[0xff; 32]),
457 GenericArray::from_slice(&[0; 12]),
458 );
459 st.seek(0x40_0000_0000);
460
461 assert!(st.try_apply_keystream(&mut [0u8; 1]).is_err());
462 }
463
464 #[test]
465 fn read_last_bytes() {
466 let mut st = Ietf::new(
467 GenericArray::from_slice(&[0xff; 32]),
468 GenericArray::from_slice(&[0; 12]),
469 );
470
471 st.seek(0x40_0000_0000 - 10);
472 st.apply_keystream(&mut [0u8; 10]);
473 assert!(st.try_apply_keystream(&mut [0u8; 1]).is_err());
474
475 st.seek(0x40_0000_0000 - 10);
476 assert!(st.try_apply_keystream(&mut [0u8; 11]).is_err());
477 }
478
479 #[test]
480 fn seek_consistency() {
481 let mut st = Ietf::new(
482 GenericArray::from_slice(&[50; 32]),
483 GenericArray::from_slice(&[44; 12]),
484 );
485
486 let mut continuous = [0u8; 1000];
487 st.apply_keystream(&mut continuous);
488
489 let mut chunks = [0u8; 1000];
490
491 st.seek(128);
492 st.apply_keystream(&mut chunks[128..300]);
493
494 st.seek(0);
495 st.apply_keystream(&mut chunks[0..10]);
496
497 st.seek(300);
498 st.apply_keystream(&mut chunks[300..533]);
499
500 st.seek(533);
501 st.apply_keystream(&mut chunks[533..]);
502
503 st.seek(10);
504 st.apply_keystream(&mut chunks[10..128]);
505
506 assert_eq!(&continuous[..], &chunks[..]);
507 }
508
509 #[test]
510 fn wide_matches_narrow() {
511 let key = hex!("fa44478c59ca70538e3549096ce8b523232c50d9e8e8d10c203ef6c8d07098a5");
512 let nonce = hex!("8d3a0d6d7827c007");
513 let mut buf = [0; 2048];
514 let mut state = ChaCha20::new(
515 GenericArray::from_slice(&key),
516 GenericArray::from_slice(&nonce),
517 );
518
519 let lens = [
520 2048, 2047, 1537, 1536, 1535, 1025, 1024, 1023, 768, 513, 512, 511, 200, 100, 50,
521 ];
522
523 for &len in &lens {
524 let buf = &mut buf[0..len];
525
526 // encrypt with hybrid wide/narrow
527 state.seek(0);
528 state.apply_keystream(buf);
529 state.seek(0);
530 // decrypt with narrow only
531 state.try_apply_keystream_narrow(buf).unwrap();
532 for &byte in buf.iter() {
533 assert_eq!(byte, 0);
534 }
535
536 // encrypt with hybrid wide/narrow
537 let offset = 0x3fffffff70u64;
538 state.seek(offset);
539 state.apply_keystream(buf);
540 // decrypt with narrow only
541 state.seek(offset);
542 state.try_apply_keystream_narrow(buf).unwrap();
543 for &byte in buf.iter() {
544 assert_eq!(byte, 0);
545 }
546 }
547 }
548}