crypto_api_chachapoly/
chacha20_ietf.rs

1use crate::core::chacha20::chacha20_ietf_block;
2use crypto_api::{
3    cipher::{ CipherInfo, Cipher },
4    rng::{ SecureRng, SecKeyGen }
5};
6use std::{ cmp::min, error::Error };
7
8
9/// The maximum amount of bytes that can be processed with one key/nonce combination
10#[cfg(target_pointer_width = "64")]
11pub const CHACHA20_MAX: usize = 4_294_967_296 * 64; // 2^32 * BLOCK_SIZE
12/// The maximum amount of bytes that can be processed with one key/nonce combination
13#[cfg(target_pointer_width = "32")]
14pub const CHACHA20_MAX: usize = usize::max_value(); // 2^32 - 1
15
16
17/// The size of a ChaCha20 key (256 bits/32 bytes)
18pub const CHACHA20_KEY: usize = 32;
19/// The size of a ChaCha20 nonce (96 bits/12 bytes)
20pub const CHACHA20_NONCE: usize = 12;
21
22
23/// An implementation of [ChaCha20 (IETF-version)](https://tools.ietf.org/html/rfc8439)
24pub struct ChaCha20Ietf;
25impl ChaCha20Ietf {
26    /// Creates a `Cipher` instance with `ChaCha20Ietf` as underlying cipher
27    pub fn cipher() -> Box<dyn Cipher> {
28        Box::new(Self)
29    }
30    
31    /// XORs the bytes in `data` with the ChaCha20 keystream for `key` and `nonce` starting at the
32    /// `n`th block
33    ///
34    /// ## Warning:
35    /// This function panics if
36    ///  - `key` is smaller or larger than 32 bytes/256 bits
37    ///  - `nonce` is smaller or larger than 12 bytes/96 bits
38    ///  - `n` exceeds `2^32 - 1` (which means that `data` must be smaller than `(2^32 - n) * 64`)
39    ///
40    /// __Consider using the `crypto_api`-interface instead of calling this function directly__
41    pub fn xor(key: &[u8], nonce: &[u8], mut n: u32, mut data: &mut[u8]) {
42        // Verify input
43        assert_eq!(CHACHA20_KEY, key.len());
44        assert_eq!(CHACHA20_NONCE, nonce.len());
45        
46        // XOR `data`
47        let mut buf = vec![0; 64];
48        while !data.is_empty() {
49            // Compute next block
50            chacha20_ietf_block(key, nonce, n, &mut buf);
51            n = n.checked_add(1).expect("The ChaCha20-IETF block counter must not exceed 2^32 - 1");
52            
53            // Xor block
54            let to_xor = min(data.len(), buf.len());
55            (0..to_xor).for_each(|i| data[i] = xor!(data[i], buf[i]));
56            data = &mut data[to_xor..];
57        }
58    }
59}
60impl SecKeyGen for ChaCha20Ietf {
61    fn new_sec_key(&self, buf: &mut[u8], rng: &mut dyn SecureRng) -> Result<usize, Box<dyn Error + 'static>> {
62        // Verify input
63        vfy_keygen!(CHACHA20_KEY => buf);
64        
65        // Generate key
66        rng.random(&mut buf[..CHACHA20_KEY])?;
67        Ok(CHACHA20_KEY)
68    }
69}
70impl Cipher for ChaCha20Ietf {
71    fn info(&self) -> CipherInfo {
72        CipherInfo {
73            name: "ChaCha20Ietf", is_otc: true,
74            key_len_r: CHACHA20_KEY..(CHACHA20_KEY + 1),
75            nonce_len_r: CHACHA20_NONCE..(CHACHA20_NONCE + 1),
76            aead_tag_len_r: 0..(0 + 1)
77        }
78    }
79    
80    fn encrypted_len_max(&self, plaintext_len: usize) -> usize {
81        plaintext_len
82    }
83    
84    fn encrypt(&self, buf: &mut[u8], plaintext_len: usize, key: &[u8], nonce: &[u8])
85        -> Result<usize, Box<dyn Error + 'static>>
86    {
87        // Verify input
88        vfy_enc!(
89            key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
90            plaintext_len => [buf, CHACHA20_MAX]
91        );
92        
93        // Encrypt the data
94        Self::xor(key, nonce, 0, &mut buf[..plaintext_len]);
95        Ok(plaintext_len)
96    }
97    fn encrypt_to(&self, buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8])
98        -> Result<usize, Box<dyn Error + 'static>>
99    {
100        // Verify input
101        vfy_enc!(
102            key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
103            plaintext => [buf, CHACHA20_MAX]
104        );
105        
106        // Fill `buf` and encrypt the data in place
107        buf[..plaintext.len()].copy_from_slice(plaintext);
108        Self::xor(key, nonce, 0, &mut buf[..plaintext.len()]);
109        Ok(plaintext.len())
110    }
111    
112    fn decrypt(&self, buf: &mut[u8], ciphertext_len: usize, key: &[u8], nonce: &[u8])
113        -> Result<usize, Box<dyn Error + 'static>>
114    {
115        // Verify input
116        vfy_dec!(
117            key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
118            ciphertext_len => [buf, CHACHA20_MAX]
119        );
120        
121        // Encrypt the data
122        Self::xor(key, nonce, 0, &mut buf[..ciphertext_len]);
123        Ok(ciphertext_len)
124    }
125    fn decrypt_to(&self, buf: &mut[u8], ciphertext: &[u8], key: &[u8], nonce: &[u8])
126        -> Result<usize, Box<dyn Error + 'static>>
127    {
128        // Verify input
129        vfy_dec!(
130            key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
131            ciphertext => [buf, CHACHA20_MAX]
132        );
133        
134        // Fill `buf` and encrypt the data in place
135        buf[..ciphertext.len()].copy_from_slice(ciphertext);
136        Self::xor(key, nonce, 0, &mut buf[..ciphertext.len()]);
137        Ok(ciphertext.len())
138    }
139}