crypto_api_chachapoly/
xchacha20.rs1use crate::{
2 chacha20_ietf::CHACHA20_KEY,
3 core::chacha20::{ hchacha20_hash, chacha20_block }
4};
5use crypto_api::{
6 cipher::{ CipherInfo, Cipher },
7 rng::{ SecureRng, SecKeyGen }
8};
9use std::{ cmp::min, error::Error };
10
11
12pub const XCHACHA20_MAX: usize = usize::max_value();
15
16pub const XCHACHA20_KEY: usize = CHACHA20_KEY;
18pub const XCHACHA20_NONCE: usize = 24;
20
21
22pub struct XChaCha20;
24impl XChaCha20 {
25 pub fn cipher() -> Box<dyn Cipher> {
27 Box::new(Self)
28 }
29
30 pub fn xor(key: &[u8], nonce: &[u8], mut n: u64, mut data: &mut[u8]) {
41 assert_eq!(XCHACHA20_KEY, key.len());
43 assert_eq!(XCHACHA20_NONCE, nonce.len());
44
45 let (x_nonce, nonce) = nonce.split_at(16);
47 let mut x_key = vec![0; 32];
48 hchacha20_hash(key, x_nonce, &mut x_key);
49
50 let mut buf = vec![0; 64];
52 while !data.is_empty() {
53 chacha20_block(&x_key, nonce, n, &mut buf);
55 n = n.checked_add(1).expect("The ChaCha20 block counter must not exceed 2^64 - 1");
56
57 let to_xor = min(data.len(), buf.len());
59 (0..to_xor).for_each(|i| data[i] = xor!(data[i], buf[i]));
60 data = &mut data[to_xor..];
61 }
62 }
63}
64impl SecKeyGen for XChaCha20 {
65 fn new_sec_key(&self, buf: &mut[u8], rng: &mut dyn SecureRng) -> Result<usize, Box<dyn Error + 'static>> {
66 vfy_keygen!(XCHACHA20_KEY => buf);
68
69 rng.random(&mut buf[..XCHACHA20_KEY])?;
71 Ok(XCHACHA20_KEY)
72 }
73}
74impl Cipher for XChaCha20 {
75 fn info(&self) -> CipherInfo {
76 CipherInfo {
77 name: "XChaCha20", is_otc: true,
78 key_len_r: XCHACHA20_KEY..(XCHACHA20_KEY + 1),
79 nonce_len_r: XCHACHA20_NONCE..(XCHACHA20_NONCE + 1),
80 aead_tag_len_r: 0..(0 + 1)
81 }
82 }
83
84 fn encrypted_len_max(&self, plaintext_len: usize) -> usize {
85 plaintext_len
86 }
87
88 fn encrypt(&self, buf: &mut[u8], plaintext_len: usize, key: &[u8], nonce: &[u8])
89 -> Result<usize, Box<dyn Error + 'static>>
90 {
91 vfy_enc!(
93 key => [XCHACHA20_KEY], nonce => [XCHACHA20_NONCE],
94 plaintext_len => [buf, XCHACHA20_MAX]
95 );
96
97 Self::xor(key, nonce, 0, &mut buf[..plaintext_len]);
99 Ok(plaintext_len)
100 }
101 fn encrypt_to(&self, buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8])
102 -> Result<usize, Box<dyn Error + 'static>>
103 {
104 vfy_enc!(
106 key => [XCHACHA20_KEY], nonce => [XCHACHA20_NONCE],
107 plaintext => [buf, XCHACHA20_MAX]
108 );
109
110 buf[..plaintext.len()].copy_from_slice(plaintext);
112 Self::xor(key, nonce, 0, &mut buf[..plaintext.len()]);
113 Ok(plaintext.len())
114 }
115
116 fn decrypt(&self, buf: &mut[u8], ciphertext_len: usize, key: &[u8], nonce: &[u8])
117 -> Result<usize, Box<dyn Error + 'static>>
118 {
119 vfy_dec!(
121 key => [XCHACHA20_KEY], nonce => [XCHACHA20_NONCE],
122 ciphertext_len => [buf, XCHACHA20_MAX]
123 );
124
125 Self::xor(key, nonce, 0, &mut buf[..ciphertext_len]);
127 Ok(ciphertext_len)
128 }
129 fn decrypt_to(&self, buf: &mut[u8], ciphertext: &[u8], key: &[u8], nonce: &[u8])
130 -> Result<usize, Box<dyn Error + 'static>>
131 {
132 vfy_dec!(
134 key => [XCHACHA20_KEY], nonce => [XCHACHA20_NONCE],
135 ciphertext => [buf, XCHACHA20_MAX]
136 );
137
138 buf[..ciphertext.len()].copy_from_slice(ciphertext);
140 Self::xor(key, nonce, 0, &mut buf[..ciphertext.len()]);
141 Ok(ciphertext.len())
142 }
143}