1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::core::chacha20::chacha20_ietf_block;
use crypto_api::{
cipher::{ CipherInfo, Cipher },
rng::{ SecureRng, SecKeyGen }
};
use std::{ cmp::min, error::Error };
#[cfg(target_pointer_width = "64")]
pub const CHACHA20_MAX: usize = 4_294_967_296 * 64;
#[cfg(target_pointer_width = "32")]
pub const CHACHA20_MAX: usize = usize::max_value();
pub const CHACHA20_KEY: usize = 32;
pub const CHACHA20_NONCE: usize = 12;
pub struct ChaCha20Ietf;
impl ChaCha20Ietf {
pub fn cipher() -> Box<dyn Cipher> {
Box::new(Self)
}
pub fn xor(key: &[u8], nonce: &[u8], mut n: u32, mut data: &mut[u8]) {
assert_eq!(CHACHA20_KEY, key.len());
assert_eq!(CHACHA20_NONCE, nonce.len());
let mut buf = vec![0; 64];
while !data.is_empty() {
chacha20_ietf_block(key, nonce, n, &mut buf);
n = n.checked_add(1).expect("The ChaCha20-IETF block counter must not exceed 2^32 - 1");
let to_xor = min(data.len(), buf.len());
(0..to_xor).for_each(|i| data[i] = xor!(data[i], buf[i]));
data = &mut data[to_xor..];
}
}
}
impl SecKeyGen for ChaCha20Ietf {
fn new_sec_key(&self, buf: &mut[u8], rng: &mut dyn SecureRng)
-> Result<usize, Box<dyn Error + 'static>>
{
vfy_keygen!(CHACHA20_KEY => buf);
rng.random(&mut buf[..CHACHA20_KEY])?;
Ok(CHACHA20_KEY)
}
}
impl Cipher for ChaCha20Ietf {
fn info(&self) -> CipherInfo {
CipherInfo {
name: "ChaCha20Ietf", is_otc: true,
key_len_r: CHACHA20_KEY..CHACHA20_KEY,
nonce_len_r: CHACHA20_NONCE..CHACHA20_NONCE,
aead_tag_len_r: 0..0
}
}
fn encrypted_len_max(&self, plaintext_len: usize) -> usize {
plaintext_len
}
fn encrypt(&self, buf: &mut[u8], plaintext_len: usize, key: &[u8], nonce: &[u8])
-> Result<usize, Box<dyn Error + 'static>>
{
vfy_enc!(
key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
plaintext_len => [buf, CHACHA20_MAX]
);
Self::xor(key, nonce, 0, &mut buf[..plaintext_len]);
Ok(plaintext_len)
}
fn encrypt_to(&self, buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8])
-> Result<usize, Box<dyn Error + 'static>>
{
vfy_enc!(
key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
plaintext => [buf, CHACHA20_MAX]
);
buf[..plaintext.len()].copy_from_slice(plaintext);
Self::xor(key, nonce, 0, &mut buf[..plaintext.len()]);
Ok(plaintext.len())
}
fn decrypt(&self, buf: &mut[u8], ciphertext_len: usize, key: &[u8], nonce: &[u8])
-> Result<usize, Box<dyn Error + 'static>>
{
vfy_dec!(
key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
ciphertext_len => [buf, CHACHA20_MAX]
);
Self::xor(key, nonce, 0, &mut buf[..ciphertext_len]);
Ok(ciphertext_len)
}
fn decrypt_to(&self, buf: &mut[u8], ciphertext: &[u8], key: &[u8], nonce: &[u8])
-> Result<usize, Box<dyn Error + 'static>>
{
vfy_dec!(
key => [CHACHA20_KEY], nonce => [CHACHA20_NONCE],
ciphertext => [buf, CHACHA20_MAX]
);
buf[..ciphertext.len()].copy_from_slice(ciphertext);
Self::xor(key, nonce, 0, &mut buf[..ciphertext.len()]);
Ok(ciphertext.len())
}
}