1#![cfg_attr(not(test), no_std)]
28
29const WORD_1: u32 = 0x61707865;
30const WORD_2: u32 = 0x3320646e;
31const WORD_3: u32 = 0x79622d32;
32const WORD_4: u32 = 0x6b206574;
33const CHACHA_ROUND_INDICIES: [(usize, usize, usize, usize); 8] = [
34 (0, 4, 8, 12),
35 (1, 5, 9, 13),
36 (2, 6, 10, 14),
37 (3, 7, 11, 15),
38 (0, 5, 10, 15),
39 (1, 6, 11, 12),
40 (2, 7, 8, 13),
41 (3, 4, 9, 14),
42];
43const CHACHA_BLOCKSIZE: usize = 64;
44
45#[derive(Debug)]
47pub struct ChaCha20 {
48 key: [u8; 32],
49 nonce: [u8; 12],
50 inner: u32,
51 seek: usize,
52}
53
54impl ChaCha20 {
55 pub fn new(key: [u8; 32], nonce: [u8; 12], seek: u32) -> Self {
57 let inner = seek / 64;
58 let seek = (seek % 64) as usize;
59 ChaCha20 {
60 key,
61 nonce,
62 inner,
63 seek,
64 }
65 }
66
67 pub fn new_from_block(key: [u8; 32], nonce: [u8; 12], block: u32) -> Self {
69 let inner = block;
70 let seek = 0;
71 ChaCha20 {
72 key,
73 nonce,
74 inner,
75 seek,
76 }
77 }
78
79 pub fn apply_keystream<'a>(&'a mut self, to: &'a mut [u8]) -> &[u8] {
81 let num_full_blocks = to.len() / CHACHA_BLOCKSIZE;
82 let mut j = 0;
83 while j < num_full_blocks {
84 let kstream = keystream_at_slice(self.key, self.nonce, self.inner, self.seek);
85 for (c, k) in to[j * CHACHA_BLOCKSIZE..(j + 1) * CHACHA_BLOCKSIZE]
86 .iter_mut()
87 .zip(kstream.iter())
88 {
89 *c ^= *k
90 }
91 j += 1;
92 self.inner += 1;
93 }
94 if to.len() % 64 > 0 {
95 let kstream = keystream_at_slice(self.key, self.nonce, self.inner, self.seek);
96 for (c, k) in to[j * CHACHA_BLOCKSIZE..].iter_mut().zip(kstream.iter()) {
97 *c ^= *k
98 }
99 self.inner += 1;
100 }
101 to
102 }
103
104 pub fn get_keystream(&mut self, block: u32) -> [u8; 64] {
106 self.block(block);
107 keystream_at_slice(self.key, self.nonce, self.inner, self.seek)
108 }
109
110 pub fn seek(&mut self, seek: u32) {
112 self.inner = seek / 64;
113 self.seek = (seek % 64) as usize;
114 }
115
116 pub fn block(&mut self, block: u32) {
118 self.inner = block;
119 self.seek = 0;
120 }
121}
122
123fn quarter_round(state: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize) {
124 state[a] = state[a].wrapping_add(state[b]);
125 state[d] = (state[d] ^ state[a]).rotate_left(16);
126 state[c] = state[c].wrapping_add(state[d]);
127 state[b] = (state[b] ^ state[c]).rotate_left(12);
128 state[a] = state[a].wrapping_add(state[b]);
129 state[d] = (state[d] ^ state[a]).rotate_left(8);
130 state[c] = state[c].wrapping_add(state[d]);
131 state[b] = (state[b] ^ state[c]).rotate_left(7);
132}
133
134fn double_round(state: &mut [u32; 16]) {
135 for (a, b, c, d) in CHACHA_ROUND_INDICIES {
136 quarter_round(state, a, b, c, d);
137 }
138}
139
140fn chacha_block(state: &mut [u32; 16]) {
141 let initial_state = *state;
142 for _ in 0..10 {
143 double_round(state)
144 }
145 for (modified, initial) in state.iter_mut().zip(initial_state.iter()) {
146 *modified = modified.wrapping_add(*initial)
147 }
148}
149
150fn prepare_state(key: [u8; 32], nonce: [u8; 12], count: u32) -> [u32; 16] {
151 let mut state: [u32; 16] = [0; 16];
152 state[0] = WORD_1;
153 state[1] = WORD_2;
154 state[2] = WORD_3;
155 state[3] = WORD_4;
156 state[4] = u32::from_le_bytes(key[0..4].try_into().expect("Valid slice of 32 byte array."));
157 state[5] = u32::from_le_bytes(key[4..8].try_into().expect("Valid slice of 32 byte array."));
158 state[6] = u32::from_le_bytes(
159 key[8..12]
160 .try_into()
161 .expect("Valid slice of 32 byte array."),
162 );
163 state[7] = u32::from_le_bytes(
164 key[12..16]
165 .try_into()
166 .expect("Valid slice of 32 byte array."),
167 );
168 state[8] = u32::from_le_bytes(
169 key[16..20]
170 .try_into()
171 .expect("Valid slice of 32 byte array."),
172 );
173 state[9] = u32::from_le_bytes(
174 key[20..24]
175 .try_into()
176 .expect("Valid slice of 32 byte array."),
177 );
178 state[10] = u32::from_le_bytes(
179 key[24..28]
180 .try_into()
181 .expect("Valid slice of 32 byte array."),
182 );
183 state[11] = u32::from_le_bytes(
184 key[28..32]
185 .try_into()
186 .expect("Valid slice of 32 byte array."),
187 );
188 state[12] = count;
189 state[13] = u32::from_le_bytes(
190 nonce[0..4]
191 .try_into()
192 .expect("Valid slice of 32 byte array."),
193 );
194 state[14] = u32::from_le_bytes(
195 nonce[4..8]
196 .try_into()
197 .expect("Valid slice of 32 byte array."),
198 );
199 state[15] = u32::from_le_bytes(
200 nonce[8..12]
201 .try_into()
202 .expect("Valid slice of 32 byte array."),
203 );
204 state
205}
206
207fn keystream_from_state(state: &mut [u32; 16]) -> [u8; 64] {
208 let mut keystream: [u8; 64] = [0; 64];
209 let mut index = 0;
210 for &element in state.iter() {
211 let bytes = element.to_le_bytes();
212 keystream[index..index + 4].copy_from_slice(&bytes);
213 index += 4;
214 }
215 keystream
216}
217
218fn keystream_at_slice(key: [u8; 32], nonce: [u8; 12], inner: u32, seek: usize) -> [u8; 64] {
219 let mut keystream: [u8; 128] = [0; 128];
220 let mut state = prepare_state(key, nonce, inner);
221 chacha_block(&mut state);
222 let first_half = keystream_from_state(&mut state);
223 let mut state = prepare_state(key, nonce, inner + 1);
224 chacha_block(&mut state);
225 let second_half = keystream_from_state(&mut state);
226 keystream[..64].copy_from_slice(&first_half);
227 keystream[64..].copy_from_slice(&second_half);
228 let kstream: [u8; 64] = keystream[seek..seek + 64].try_into().expect("msg");
229 kstream
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235 use chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
236 use hex;
237 use rand::Rng;
238
239 #[test]
240 fn test_quater_round() {
241 let a: u32 = 0x11111111;
242 let b: u32 = 0x01020304;
243 let c: u32 = 0x9b8d6f43;
244 let d: u32 = 0x01234567;
245 let mut state = [a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d];
246 quarter_round(&mut state, 0, 1, 2, 3);
247 assert_eq!(hex::encode(state[0].to_be_bytes()), "ea2a92f4");
248 assert_eq!(hex::encode(state[1].to_be_bytes()), "cb1cf8ce");
249 assert_eq!(hex::encode(state[2].to_be_bytes()), "4581472e");
250 assert_eq!(hex::encode(state[3].to_be_bytes()), "5881c4bb");
251 }
252
253 #[test]
254 fn test_quater_round_on_block() {
255 let a: u32 = 0x879531e0;
256 let b: u32 = 0xc5ecf37d;
257 let c: u32 = 0x516461b1;
258 let d: u32 = 0xc9a62f8a;
259 let e: u32 = 0x44c20ef3;
260 let f: u32 = 0x3390af7f;
261 let g: u32 = 0xd9fc690b;
262 let h: u32 = 0x2a5f714c;
263 let i: u32 = 0x53372767;
264 let j: u32 = 0xb00a5631;
265 let k: u32 = 0x974c541a;
266 let l: u32 = 0x359e9963;
267 let m: u32 = 0x5c971061;
268 let n: u32 = 0x3d631689;
269 let o: u32 = 0x2098d9d6;
270 let p: u32 = 0x91dbd320;
271 let mut state = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
272 quarter_round(&mut state, 2, 7, 8, 13);
273 assert_eq!(hex::encode(state[2].to_be_bytes()), "bdb886dc");
274 }
275
276 #[test]
277 fn test_block_fn() {
278 let a: u32 = 0x61707865;
279 let b: u32 = 0x3320646e;
280 let c: u32 = 0x79622d32;
281 let d: u32 = 0x6b206574;
282 let e: u32 = 0x03020100;
283 let f: u32 = 0x07060504;
284 let g: u32 = 0x0b0a0908;
285 let h: u32 = 0x0f0e0d0c;
286 let i: u32 = 0x13121110;
287 let j: u32 = 0x17161514;
288 let k: u32 = 0x1b1a1918;
289 let l: u32 = 0x1f1e1d1c;
290 let m: u32 = 0x00000001;
291 let n: u32 = 0x09000000;
292 let o: u32 = 0x4a000000;
293 let p: u32 = 0x00000000;
294 let mut state = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
295 chacha_block(&mut state);
296 assert_eq!(hex::encode(state[0].to_be_bytes()), "e4e7f110");
297 assert_eq!(hex::encode(state[1].to_be_bytes()), "15593bd1");
298 assert_eq!(hex::encode(state[2].to_be_bytes()), "1fdd0f50");
299 assert_eq!(hex::encode(state[3].to_be_bytes()), "c47120a3");
300 assert_eq!(hex::encode(state[4].to_be_bytes()), "c7f4d1c7");
301 assert_eq!(hex::encode(state[5].to_be_bytes()), "0368c033");
302 assert_eq!(hex::encode(state[6].to_be_bytes()), "9aaa2204");
303 assert_eq!(hex::encode(state[7].to_be_bytes()), "4e6cd4c3");
304 assert_eq!(hex::encode(state[8].to_be_bytes()), "466482d2");
305 assert_eq!(hex::encode(state[9].to_be_bytes()), "09aa9f07");
306 assert_eq!(hex::encode(state[10].to_be_bytes()), "05d7c214");
307 assert_eq!(hex::encode(state[11].to_be_bytes()), "a2028bd9");
308 assert_eq!(hex::encode(state[12].to_be_bytes()), "d19c12b5");
309 assert_eq!(hex::encode(state[13].to_be_bytes()), "b94e16de");
310 assert_eq!(hex::encode(state[14].to_be_bytes()), "e883d0cb");
311 assert_eq!(hex::encode(state[15].to_be_bytes()), "4e3c50a2");
312 }
313
314 #[test]
315 fn test_block_serialization() {
316 let a: u32 = 0x61707865;
317 let b: u32 = 0x3320646e;
318 let c: u32 = 0x79622d32;
319 let d: u32 = 0x6b206574;
320 let e: u32 = 0x03020100;
321 let f: u32 = 0x07060504;
322 let g: u32 = 0x0b0a0908;
323 let h: u32 = 0x0f0e0d0c;
324 let i: u32 = 0x13121110;
325 let j: u32 = 0x17161514;
326 let k: u32 = 0x1b1a1918;
327 let l: u32 = 0x1f1e1d1c;
328 let m: u32 = 0x00000001;
329 let n: u32 = 0x09000000;
330 let o: u32 = 0x4a000000;
331 let p: u32 = 0x00000000;
332 let mut state = [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
333 chacha_block(&mut state);
334 assert_eq!(hex::encode(state[7].to_le_bytes()), "c3d46c4e");
335 }
336
337 #[test]
338 fn test_prepare_state() {
339 let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
340 .unwrap();
341 let key: [u8; 32] = key.try_into().unwrap();
342 let nonce = hex::decode("000000090000004a00000000").unwrap();
343 let nonce: [u8; 12] = nonce.try_into().unwrap();
344 let count = 1;
345 let state = prepare_state(key, nonce, count);
346 assert_eq!(hex::encode(state[4].to_be_bytes()), "03020100");
347 assert_eq!(hex::encode(state[10].to_be_bytes()), "1b1a1918");
348 assert_eq!(hex::encode(state[14].to_be_bytes()), "4a000000");
349 assert_eq!(hex::encode(state[15].to_be_bytes()), "00000000");
350 assert_eq!(hex::encode(state[12].to_be_bytes()), "00000001")
351 }
352
353 #[test]
354 fn test_small_plaintext() {
355 let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
356 .unwrap();
357 let key: [u8; 32] = key.try_into().unwrap();
358 let nonce = hex::decode("000000090000004a00000000").unwrap();
359 let nonce: [u8; 12] = nonce.try_into().unwrap();
360 let count = 1;
361 let mut chacha = ChaCha20::new(key, nonce, count);
362 let mut binding = [8; 3];
363 let to = binding.as_mut_slice();
364 chacha.apply_keystream(to);
365 let mut chacha = ChaCha20::new(key, nonce, count);
366 chacha.apply_keystream(to);
367 assert_eq!([8; 3], to);
368 }
369
370 #[test]
371 fn test_modulo_64() {
372 let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
373 .unwrap();
374 let key: [u8; 32] = key.try_into().unwrap();
375 let nonce = hex::decode("000000000000004a00000000").unwrap();
376 let nonce: [u8; 12] = nonce.try_into().unwrap();
377 let count = 1;
378 let mut chacha = ChaCha20::new(key, nonce, count);
379 let mut binding = [8; 64];
380 let to = binding.as_mut_slice();
381 chacha.apply_keystream(to);
382 let mut chacha = ChaCha20::new(key, nonce, count);
383 chacha.apply_keystream(to);
384 assert_eq!([8; 64], to);
385 }
386
387 #[test]
388 fn test_rfc_standard() {
389 let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
390 .unwrap();
391 let key: [u8; 32] = key.try_into().unwrap();
392 let nonce = hex::decode("000000000000004a00000000").unwrap();
393 let nonce: [u8; 12] = nonce.try_into().unwrap();
394 let count = 64;
395 let mut chacha = ChaCha20::new(key, nonce, count);
396 let mut binding = *b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
397 let to = binding.as_mut_slice();
398 chacha.apply_keystream(to);
399 assert_eq!(to, hex::decode("6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42874d").unwrap());
400 let mut chacha = ChaCha20::new(key, nonce, count);
401 chacha.apply_keystream(to);
402 let binding = *b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
403 assert_eq!(binding, to);
404 }
405
406 #[test]
407 fn test_new_from_block() {
408 let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
409 .unwrap();
410 let key: [u8; 32] = key.try_into().unwrap();
411 let nonce = hex::decode("000000000000004a00000000").unwrap();
412 let nonce: [u8; 12] = nonce.try_into().unwrap();
413 let block: u32 = 1;
414 let mut chacha = ChaCha20::new_from_block(key, nonce, block);
415 let mut binding = *b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
416 let to = binding.as_mut_slice();
417 chacha.apply_keystream(to);
418 assert_eq!(to, hex::decode("6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42874d").unwrap());
419 chacha.block(block);
420 chacha.apply_keystream(to);
421 let binding = *b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
422 assert_eq!(binding, to);
423 }
424
425 fn gen_garbage(garbage_len: u32) -> Vec<u8> {
426 let mut rng = rand::thread_rng();
427 let buffer: Vec<u8> = (0..garbage_len).map(|_| rng.gen()).collect();
428 buffer
429 }
430
431 #[test]
432 fn test_fuzz_other() {
433 for _ in 0..100 {
434 let garbage_key = gen_garbage(32);
435 let key = garbage_key.as_slice().try_into().unwrap();
436 let garbage_nonce = gen_garbage(12);
437 let nonce = garbage_nonce.as_slice().try_into().unwrap();
438 for i in 0..10 {
439 let count: u32 = i * 11;
440 let mut chacha = ChaCha20::new(key, nonce, count);
441 let message = gen_garbage(129);
442 let mut message2 = message.clone();
443 let msg = message2.as_mut_slice();
444 chacha.apply_keystream(msg);
445 let mut cipher = chacha20::ChaCha20::new_from_slices(&key, &nonce)
446 .expect("Valid keys and nonce.");
447 let mut buffer = message;
448 cipher.seek(count);
449 cipher.apply_keystream(&mut buffer);
450 assert_eq!(buffer.as_slice(), msg);
451 }
452 }
453 }
454}