1use {
55 core::mem,
56 alloc::{
57 string::String,
58 vec::Vec,
59 },
60 crate::{
61 Bytes,
62 Result,
63 chacha::{
64 self,
65 Chacha,
66 Key,
67 TWENTY,
68 word_array::{self, WORD_SIZE},
69 },
70 },
71 super::{
72 Poly1305,
73 Tag,
74 chacha20::{self, Args, Counter},
75 encrypted_data_buffer::EncryptedDataBuffer,
76 },
77};
78
79#[cfg(not(feature="std"))]
80use crate::io::Write;
81
82#[cfg(feature="std")]
83use {
84 std::io::{Read, Write},
85 crate::IoResult,
86};
87
88#[cfg(feature="simd")]
89use crate::chacha::salsa20_simd::run_quarter_rounds;
90
91#[cfg(not(feature="simd"))]
92use crate::chacha::salsa20::run_quarter_rounds;
93
94pub type Nonce = [u8; 24];
102
103pub unsafe fn make_encrypter<K, N, A, W>(key: K, nonce: N, aad: Option<A>, output: W) -> Result<Poly1305<&'static [u8], W>>
105where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, W: Write {
106 unsafe {
107 make_encrypter_with_counter(key, nonce, aad, output, Counter::DEFAULT)
108 }
109}
110
111unsafe fn make_encrypter_with_counter<K, N, A, W>(key: K, nonce: N, aad: Option<A>, output: W, counter: Counter) ->
113Result<Poly1305<&'static [u8], W>>
114where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, W: Write {
115 let args = make_args(true, key, nonce, aad, output, counter)?;
116 Ok(Poly1305 {
117 encrypted_data_buffer: None,
118 chacha20: args.chacha20,
119 aad_len: args.aad_len,
120 s: args.s,
121 output_size: u64::MIN,
122 })
123}
124
125pub unsafe fn make_decrypter<K, N, A, T, W>(key: K, nonce: N, aad: Option<A>, authenticated_tag: T, output: W) -> Result<Poly1305<T, W>>
129where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, W: Write {
130 unsafe {
131 make_decrypter_with_counter(key, nonce, aad, authenticated_tag, output, Counter::DEFAULT)
132 }
133}
134
135unsafe fn make_decrypter_with_counter<K, N, A, T, W>(key: K, nonce: N, aad: Option<A>, authenticated_tag: T, output: W, counter: Counter)
136-> Result<Poly1305<T, W>>
137where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, W: Write {
138 let args = make_args(false, key, nonce, aad, output, counter)?;
139 Ok(Poly1305 {
140 encrypted_data_buffer: Some(EncryptedDataBuffer::new(authenticated_tag, args.tag, args.r)),
141 chacha20: args.chacha20,
142 aad_len: args.aad_len,
143 s: args.s,
144 output_size: u64::MIN,
145 })
146}
147
148fn make_args<K, N, A, W>(for_encrypter: bool, key: K, nonce: N, aad: Option<A>, output: W, counter: Counter) -> Result<Args<W>>
150where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, W: Write {
151 let (key, nonce) = make_key_and_chacha20_nonce(key, nonce)?;
152 chacha20::make_args(for_encrypter, key, nonce, aad, output, counter)
153}
154
155fn make_key_and_chacha20_nonce<K, N>(key: K, nonce: N) -> Result<(Key, chacha20::Nonce)> where K: AsRef<[u8]>, N: AsRef<[u8]> {
157 let key = key.as_ref();
158 let key = Key::try_from(key)
159 .map_err(|_| err!("Invalid key size: {key_len}. Required: {required}", key_len=key.len(), required=mem::size_of::<Key>()))?;
160
161 let nonce = nonce.as_ref();
162 let nonce = Nonce::try_from(nonce)
163 .map_err(|_| err!("Invalid nonce size: {nonce_len}. Required: {required}", nonce_len=nonce.len(), required=mem::size_of::<Nonce>()))?;
164
165 let key = {
166 let mut key = word_array::new(key, chacha::Nonce::try_from(&nonce[..size_of::<chacha::Nonce>()]).map_err(|_| e!())?);
167 run_quarter_rounds(&TWENTY, &mut key);
168
169 let mut tmp = Key::default();
170 macro_rules! copy { ($(($i: literal, $k: literal)),+) => {
171 $(
172 tmp[$i .. $i + WORD_SIZE].copy_from_slice(&key[$k].to_le_bytes());
173 )+
174 }}
175 copy!((0, 0), (4, 1), (8, 2), (12, 3), (16, 12), (20, 13), (24, 14), (28, 15));
176 tmp
177 };
178
179 let nonce = {
180 let mut tmp = chacha20::Nonce::default();
181 tmp[4..].copy_from_slice(&nonce[size_of::<chacha::Nonce>()..]);
182 tmp
183 };
184
185 Ok((key, nonce))
186}
187
188pub unsafe fn encrypt<'a, const X: usize, K, N, A, B, B0>(key: K, nonce: N, aad: Option<A>, bytes: B) -> Result<(Vec<u8>, Tag)>
190where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, B: Into<Bytes<'a, X, B0>>, B0: AsRef<[u8]> + 'a {
191 let mut encrypter = unsafe {
192 make_encrypter(key, nonce, aad, Vec::new())?
193 };
194 encrypter.encrypt_bytes(bytes)?;
195 encrypter.finish()
196}
197
198#[cfg(feature="std")]
202#[doc(cfg(feature="std"))]
203pub unsafe fn encrypt_stream<K, N, A, R>(key: K, nonce: N, aad: Option<A>, stream: &mut R, capacity: Option<usize>) -> IoResult<(Vec<u8>, Tag)>
204where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, R: Read {
205 let mut encrypter = unsafe {
206 make_encrypter(key, nonce, aad, Vec::with_capacity(capacity.unwrap_or(0)))?
207 };
208 crate::io::read_stream(stream, |data| {
209 encrypter.encrypt(data)?;
210 Ok(())
211 })?;
212 Ok(encrypter.finish()?)
213}
214
215pub unsafe fn decrypt<'a, const X: usize, K, N, A, T, B, B0>(key: K, nonce: N, aad: Option<A>, authenticated_tag: T, bytes: B) -> Result<Vec<u8>>
217where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, B: Into<Bytes<'a, X, B0>>, B0: AsRef<[u8]> + 'a {
218 let mut decrypter = unsafe {
219 make_decrypter(key, nonce, aad, authenticated_tag, Vec::new())?
220 };
221 decrypter.encrypt_bytes(bytes)?;
222 decrypter.finish().map(|(bytes, _)| bytes)
223}
224
225#[cfg(feature="std")]
229#[doc(cfg(feature="std"))]
230pub unsafe fn decrypt_stream<K, N, A, T, R>(key: K, nonce: N, aad: Option<A>, authenticated_tag: T, stream: &mut R, capacity: Option<usize>)
231-> IoResult<Vec<u8>>
232where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, R: Read {
233 let mut decrypter = unsafe {
234 make_decrypter(key, nonce, aad, authenticated_tag, Vec::with_capacity(capacity.unwrap_or(0)))?
235 };
236 crate::io::read_stream(stream, |data| {
237 decrypter.encrypt(data)?;
238 Ok(())
239 })?;
240 Ok(decrypter.finish()?.0)
241}
242
243pub unsafe fn decrypt_to_string<'a, const X: usize, K, N, A, T, B, B0>(key: K, nonce: N, aad: Option<A>, authenticated_tag: T, bytes: B)
245-> Result<String>
246where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, B: Into<Bytes<'a, X, B0>>, B0: AsRef<[u8]> + 'a {
247 unsafe {
248 crate::str::string_from_utf8(decrypt(key, nonce, aad, authenticated_tag, bytes)?)
249 }
250}
251
252#[cfg(feature="std")]
256#[doc(cfg(feature="std"))]
257pub unsafe fn decrypt_stream_to_string<K, N, A, T, R>(
258 key: K, nonce: N, aad: Option<A>, authenticated_tag: T, stream: &mut R, capacity: Option<usize>,
259) -> IoResult<String>
260where K: AsRef<[u8]>, N: AsRef<[u8]>, A: AsRef<[u8]>, T: AsRef<[u8]>, R: Read {
261 unsafe {
262 Ok(crate::str::string_from_utf8(decrypt_stream(key, nonce, aad, authenticated_tag, stream, capacity)?)?)
263 }
264}
265
266pub unsafe fn make_chacha20<K, N, W>(key: K, nonce: N, output: W) -> Result<Chacha<W>> where K: AsRef<[u8]>, N: AsRef<[u8]>, W: Write {
268 let (key, nonce) = make_key_and_chacha20_nonce(key, nonce)?;
269 Ok(chacha20::make_chacha20_from_key_and_nonce(key, nonce, output, Counter::DEFAULT))
270}
271
272pub unsafe fn encrypt_with_chacha20<'a, const X: usize, K, N, B, B0>(key: K, nonce: N, bytes: B) -> Result<Vec<u8>>
274where K: AsRef<[u8]>, N: AsRef<[u8]>, B: Into<Bytes<'a, X, B0>>, B0: AsRef<[u8]> + 'a {
275 let mut chacha20 = unsafe {
276 make_chacha20(key, nonce, Vec::new())?
277 };
278 chacha20.encrypt_bytes(bytes)?;
279 chacha20.finish()
280}
281
282pub unsafe fn make_chacha20_with_zero_counter<K, N, W>(key: K, nonce: N, output: W) -> Result<Chacha<W>>
284where K: AsRef<[u8]>, N: AsRef<[u8]>, W: Write {
285 let (key, nonce) = make_key_and_chacha20_nonce(key, nonce)?;
286 Ok(chacha20::make_chacha20_from_key_and_nonce(key, nonce, output, unsafe { Counter::zero() }))
287}
288
289pub unsafe fn encrypt_with_chacha20_with_zero_counter<'a, const X: usize, K, N, B, B0>(key: K, nonce: N, bytes: B) -> Result<Vec<u8>>
291where K: AsRef<[u8]>, N: AsRef<[u8]>, B: Into<Bytes<'a, X, B0>>, B0: AsRef<[u8]> + 'a {
292 let mut chacha20 = unsafe {
293 make_chacha20_with_zero_counter(key, nonce, Vec::new())?
294 };
295 chacha20.encrypt_bytes(bytes)?;
296 chacha20.finish()
297}