1 use byteorder
::{ByteOrder, LE}
;
3 use crate::guts
::generic_array
::typenum
::{Unsigned, U10, U12, U24, U32, U4, U6, U8}
;
4 use crate::guts
::generic_array
::{ArrayLength, GenericArray}
;
5 use crate::guts
::{ChaCha, Machine, BLOCK, BLOCK64, BUFSZ}
;
7 use stream_cipher
::{LoopError, NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek}
;
9 const BIG_LEN
: u64 = 0;
10 const SMALL_LEN
: u64 = 1 << 32;
26 pub struct ChaChaAny
<NonceSize
, Rounds
, IsX
> {
28 pub _nonce_size
: NonceSize
,
34 fn try_apply_keystream
<EnableWide
: AsBool
>(
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
43 self.state
.refill(drounds
, &mut self.out
);
44 self.have
+= BLOCK
as i8;
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
);
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
)..]) {
67 // Process wide chunks.
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()) {
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()) {
85 have
= BLOCK
- dd
.len();
87 self.have
= have
as i8;
92 dispatch_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
);
102 dispatch_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);
113 impl<NonceSize
, Rounds
: Unsigned
, IsX
> ChaChaAny
<NonceSize
, Rounds
, IsX
> {
114 pub fn try_apply_keystream_narrow(&mut self, data
: &mut [u8]) -> Result
<(), ()> {
116 .try_apply_keystream
::<WideDisabled
>(data
, Rounds
::U32
)
120 impl<NonceSize
, Rounds
> ChaChaAny
<NonceSize
, Rounds
, O
>
122 NonceSize
: Unsigned
+ ArrayLength
<u8> + Default
,
126 fn new(key
: &GenericArray
<u8, U32
>, nonce
: &GenericArray
<u8, NonceSize
>) -> Self {
127 let nonce_len
= nonce
.len();
130 state
: init_chacha(key
, nonce
),
133 len
: if nonce_len
== 12 { SMALL_LEN }
else { BIG_LEN }
,
134 fresh
: nonce_len
!= 12,
136 _nonce_size
: Default
::default(),
137 _rounds
: Default
::default(),
138 _is_x
: Default
::default(),
143 impl<Rounds
: Unsigned
+ Default
> ChaChaAny
<U24
, Rounds
, X
> {
144 fn new(key
: &GenericArray
<u8, U32
>, nonce
: &GenericArray
<u8, U24
>) -> Self {
147 state
: init_chacha_x(key
, nonce
, Rounds
::U32
),
153 _nonce_size
: Default
::default(),
154 _rounds
: Default
::default(),
155 _is_x
: Default
::default(),
160 impl<NonceSize
: Unsigned
, Rounds
, IsX
> ChaChaAny
<NonceSize
, Rounds
, IsX
> {
162 fn seek(&mut self, ct
: u64) {
163 if NonceSize
::U32
!= 12 {
164 seek64(&mut self.state
, ct
);
166 seek32(&mut self.state
, ct
);
171 impl<NonceSize
, Rounds
: Unsigned
, IsX
> ChaChaAny
<NonceSize
, Rounds
, IsX
> {
173 fn try_apply_keystream(&mut self, data
: &mut [u8]) -> Result
<(), ()> {
175 .try_apply_keystream
::<WideEnabled
>(data
, Rounds
::U32
)
179 impl<NonceSize
, Rounds
> NewStreamCipher
for ChaChaAny
<NonceSize
, Rounds
, O
>
181 NonceSize
: Unsigned
+ ArrayLength
<u8> + Default
,
185 type NonceSize
= NonceSize
;
188 key
: &GenericArray
<u8, Self::KeySize
>,
189 nonce
: &GenericArray
<u8, Self::NonceSize
>,
191 Self::new(key
, nonce
)
195 impl<Rounds
: Unsigned
+ Default
> NewStreamCipher
for ChaChaAny
<U24
, Rounds
, X
> {
197 type NonceSize
= U24
;
200 key
: &GenericArray
<u8, Self::KeySize
>,
201 nonce
: &GenericArray
<u8, Self::NonceSize
>,
203 Self::new(key
, nonce
)
207 impl<NonceSize
: Unsigned
, Rounds
, IsX
> SyncStreamCipherSeek
for ChaChaAny
<NonceSize
, Rounds
, IsX
> {
209 fn current_pos(&self) -> u64 {
213 fn seek(&mut self, ct
: u64) {
218 impl<NonceSize
, Rounds
: Unsigned
, IsX
> SyncStreamCipher
for ChaChaAny
<NonceSize
, Rounds
, IsX
> {
220 fn try_apply_keystream(&mut self, data
: &mut [u8]) -> Result
<(), LoopError
> {
221 Self::try_apply_keystream(self, data
).map_err(|_
| LoopError
)
229 impl AsBool
for WideEnabled
{
230 const BOOL
: bool
= true;
235 impl AsBool
for WideDisabled
{
236 const BOOL
: bool
= false;
239 dispatch_light128
!(m
, Mach
, {
240 fn init_chacha(key
: &GenericArray
<u8, U32
>, nonce
: &[u8]) -> ChaCha
{
243 if nonce
.len() == 12 {
244 LE
::read_u32(&nonce
[0..4])
248 LE
::read_u32(&nonce
[nonce
.len() - 8..nonce
.len() - 4]),
249 LE
::read_u32(&nonce
[nonce
.len() - 4..]),
251 let key0
: Mach
::u32x4
= m
.read_le(&key
[..16]);
252 let key1
: Mach
::u32x4
= m
.read_le(&key
[16..]);
261 dispatch_light128
!(m
, Mach
, {
263 key
: &GenericArray
<u8, U32
>,
264 nonce
: &GenericArray
<u8, U24
>,
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
{
275 let x
= state
.refill_rounds(rounds
);
279 LE
::read_u32(&nonce
[16..20]),
280 LE
::read_u32(&nonce
[20..24]),
284 state
.d
= ctr_nonce1
.into();
289 /// IETF RFC 7539 ChaCha. Unsuitable for messages longer than 256 GiB.
290 pub type Ietf
= ChaChaAny
<U12
, U10
, O
>;
291 /// ChaCha20, as used in several standards; from Bernstein's original publication.
292 pub type ChaCha20
= ChaChaAny
<U8
, U10
, O
>;
293 /// Similar to ChaCha20, but with fewer rounds for higher performance.
294 pub type ChaCha12
= ChaChaAny
<U8
, U6
, O
>;
295 /// Similar to ChaCha20, but with fewer rounds for higher performance.
296 pub 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.
299 pub type XChaCha20
= ChaChaAny
<U24
, U10
, X
>;
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
),
319 let offset
= 0x3fffffff70u64;
320 assert
!((offset
>> 38) != ((offset
+ 240) >> 38)); // This will overflow the small word of the counter
322 let mut result
= [0; 256];
323 state
.apply_keystream(&mut result
);
324 assert_eq
!(&expected
[..], &result
[..]);
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
),
338 let mut result
= [0u8; 100];
339 state
.apply_keystream(&mut result
);
340 assert_eq
!(&expected
[..], &result
[..]);
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
),
352 "1721c044a8a6453522dddb3143d0be3512633ca3c79bf8ccc3594cb2c2f310f7bd544f55ce0db38123412d6c45207d5cf9af0c6c680cce1f
353 7e43388d1b0346b7133c59fd6af4a5a568aa334ccdc38af5ace201df84d0a3ca225494ca6209345fcf30132e");
354 let mut result
= [0u8; 100];
355 state
.apply_keystream(&mut result
);
356 assert_eq
!(&expected
[..], &result
[..]);
361 let key
= hex
!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
362 let nonce
= hex
!("000000090000004a00000000");
365 10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
366 d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
368 let mut state
= Ietf
::new(
369 GenericArray
::from_slice(&key
),
370 GenericArray
::from_slice(&nonce
),
372 let mut result
= [0; 64];
374 state
.apply_keystream(&mut result
);
375 assert_eq
!(&expected
[..], &result
[..]);
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
),
386 let mut result
= [0; 128];
387 state
.apply_keystream(&mut result
);
389 "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
390 d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
392 assert_eq
!(&expected
[..], &result
[64..]);
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
),
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
411 assert_eq
!(&expected
[..], &buf
[64..]);
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
),
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
434 assert_eq
!(&expected
[..], &buf
[64..]);
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
),
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
[..]);
455 let mut st
= Ietf
::new(
456 GenericArray
::from_slice(&[0xff; 32]),
457 GenericArray
::from_slice(&[0; 12]),
459 st
.seek(0x40_0000_0000);
461 assert
!(st
.try_apply_keystream(&mut [0u8; 1]).is_err());
465 fn read_last_bytes() {
466 let mut st
= Ietf
::new(
467 GenericArray
::from_slice(&[0xff; 32]),
468 GenericArray
::from_slice(&[0; 12]),
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());
475 st
.seek(0x40_0000_0000 - 10);
476 assert
!(st
.try_apply_keystream(&mut [0u8; 11]).is_err());
480 fn seek_consistency() {
481 let mut st
= Ietf
::new(
482 GenericArray
::from_slice(&[50; 32]),
483 GenericArray
::from_slice(&[44; 12]),
486 let mut continuous
= [0u8; 1000];
487 st
.apply_keystream(&mut continuous
);
489 let mut chunks
= [0u8; 1000];
492 st
.apply_keystream(&mut chunks
[128..300]);
495 st
.apply_keystream(&mut chunks
[0..10]);
498 st
.apply_keystream(&mut chunks
[300..533]);
501 st
.apply_keystream(&mut chunks
[533..]);
504 st
.apply_keystream(&mut chunks
[10..128]);
506 assert_eq
!(&continuous
[..], &chunks
[..]);
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
),
520 2048, 2047, 1537, 1536, 1535, 1025, 1024, 1023, 768, 513, 512, 511, 200, 100, 50,
524 let buf
= &mut buf
[0..len
];
526 // encrypt with hybrid wide/narrow
528 state
.apply_keystream(buf
);
530 // decrypt with narrow only
531 state
.try_apply_keystream_narrow(buf
).unwrap();
532 for &byte
in buf
.iter() {
536 // encrypt with hybrid wide/narrow
537 let offset
= 0x3fffffff70u64;
539 state
.apply_keystream(buf
);
540 // decrypt with narrow only
542 state
.try_apply_keystream_narrow(buf
).unwrap();
543 for &byte
in buf
.iter() {