chacha20/
lib.rs

1//! # ChaCha20
2//!
3//! A Rust implementation of the ChaCha20 stream cipher. Complete with simple, auditable code.
4//!
5//! ## Features
6//!
7//! - [x] Stack-allocated
8//! - [x] No unsafe code blocks
9//! - [x] Zero dependencies
10//! - [x] Seek an index in the keystream or a block in the keystream.
11//!
12//! ## Usage
13//!
14//! ```rust
15//! use chacha20::ChaCha20;
16//! let key = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f").unwrap();
17//! let key: [u8; 32] = key.try_into().unwrap();
18//! let nonce = hex::decode("000000000000004a00000000").unwrap();
19//! let nonce: [u8; 12] = nonce.try_into().unwrap();
20//! let seek = 42; // start the cipher at the 42nd index
21//! let mut chacha = ChaCha20::new(key, nonce, seek);
22//! 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.";
23//! let to = binding.as_mut_slice();
24//! chacha.apply_keystream(to);
25//! chacha.seek(seek); // move the keystream index back to 42
26//! ```
27#![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/// The ChaCha20 stream cipher.
46#[derive(Debug)]
47pub struct ChaCha20 {
48    key: [u8; 32],
49    nonce: [u8; 12],
50    inner: u32,
51    seek: usize,
52}
53
54impl ChaCha20 {
55    /// Make a new instance of ChaCha20 from an index in the keystream.
56    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    /// Make a new instance of ChaCha20 from a block in the keystream.
68    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    /// Apply the keystream to a message.
80    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    /// Get the keystream block at a specified block.
105    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    /// Update the index of the keystream to an index in the keystream.
111    pub fn seek(&mut self, seek: u32) {
112        self.inner = seek / 64;
113        self.seek = (seek % 64) as usize;
114    }
115
116    /// Update the index of the keystream to a block.
117    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}