1#![allow(clippy::upper_case_acronyms)]
34
35use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result};
36use core::ops::{AddAssign, Sub};
37use generic_array::{
38 typenum::{Unsigned, U4, U5},
39 ArrayLength, GenericArray,
40};
41
42#[cfg(feature = "alloc")]
43use {crate::Payload, alloc::vec::Vec};
44
45pub type Nonce<A, S> = GenericArray<u8, NonceSize<A, S>>;
47
48pub type NonceSize<A, S> =
51 <<A as AeadCore>::NonceSize as Sub<<S as StreamPrimitive<A>>::NonceOverhead>>::Output;
52
53pub type EncryptorBE32<A> = Encryptor<A, StreamBE32<A>>;
56
57pub type DecryptorBE32<A> = Decryptor<A, StreamBE32<A>>;
60
61pub type EncryptorLE31<A> = Encryptor<A, StreamLE31<A>>;
64
65pub type DecryptorLE31<A> = Decryptor<A, StreamLE31<A>>;
68
69pub trait NewStream<A>: StreamPrimitive<A>
71where
72 A: AeadInPlace,
73 A::NonceSize: Sub<Self::NonceOverhead>,
74 NonceSize<A, Self>: ArrayLength<u8>,
75{
76 fn new(key: &Key<A>, nonce: &Nonce<A, Self>) -> Self
78 where
79 A: KeyInit,
80 Self: Sized,
81 {
82 Self::from_aead(A::new(key), nonce)
83 }
84
85 fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self;
87}
88
89pub trait StreamPrimitive<A>
96where
97 A: AeadInPlace,
98 A::NonceSize: Sub<Self::NonceOverhead>,
99 NonceSize<A, Self>: ArrayLength<u8>,
100{
101 type NonceOverhead: ArrayLength<u8>;
103
104 type Counter: AddAssign + Copy + Default + Eq;
106
107 const COUNTER_INCR: Self::Counter;
109
110 const COUNTER_MAX: Self::Counter;
112
113 fn encrypt_in_place(
115 &self,
116 position: Self::Counter,
117 last_block: bool,
118 associated_data: &[u8],
119 buffer: &mut dyn Buffer,
120 ) -> Result<()>;
121
122 fn decrypt_in_place(
124 &self,
125 position: Self::Counter,
126 last_block: bool,
127 associated_data: &[u8],
128 buffer: &mut dyn Buffer,
129 ) -> Result<()>;
130
131 #[cfg(feature = "alloc")]
134 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
135 fn encrypt<'msg, 'aad>(
136 &self,
137 position: Self::Counter,
138 last_block: bool,
139 plaintext: impl Into<Payload<'msg, 'aad>>,
140 ) -> Result<Vec<u8>> {
141 let payload = plaintext.into();
142 let mut buffer = Vec::with_capacity(payload.msg.len() + A::TagSize::to_usize());
143 buffer.extend_from_slice(payload.msg);
144 self.encrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
145 Ok(buffer)
146 }
147
148 #[cfg(feature = "alloc")]
151 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
152 fn decrypt<'msg, 'aad>(
153 &self,
154 position: Self::Counter,
155 last_block: bool,
156 ciphertext: impl Into<Payload<'msg, 'aad>>,
157 ) -> Result<Vec<u8>> {
158 let payload = ciphertext.into();
159 let mut buffer = Vec::from(payload.msg);
160 self.decrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
161 Ok(buffer)
162 }
163
164 fn encryptor(self) -> Encryptor<A, Self>
166 where
167 Self: Sized,
168 {
169 Encryptor::from_stream_primitive(self)
170 }
171
172 fn decryptor(self) -> Decryptor<A, Self>
174 where
175 Self: Sized,
176 {
177 Decryptor::from_stream_primitive(self)
178 }
179}
180
181macro_rules! impl_stream_object {
183 (
184 $name:ident,
185 $next_method:tt,
186 $next_in_place_method:tt,
187 $last_method:tt,
188 $last_in_place_method:tt,
189 $op:tt,
190 $in_place_op:tt,
191 $op_desc:expr,
192 $obj_desc:expr
193 ) => {
194 #[doc = "Stateful STREAM object which can"]
195 #[doc = $op_desc]
196 #[doc = "AEAD messages one-at-a-time."]
197 #[doc = ""]
198 #[doc = "This corresponds to the "]
199 #[doc = $obj_desc]
200 #[doc = "object as defined in the paper"]
201 #[doc = "[Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]."]
202 #[doc = ""]
203 #[doc = "[1]: https://eprint.iacr.org/2015/189.pdf"]
204 pub struct $name<A, S>
205 where
206 A: AeadInPlace,
207 S: StreamPrimitive<A>,
208 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
209 NonceSize<A, S>: ArrayLength<u8>,
210 {
211 stream: S,
213
214 position: S::Counter,
216 }
217
218 impl<A, S> $name<A, S>
219 where
220 A: AeadInPlace,
221 S: StreamPrimitive<A>,
222 A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
223 NonceSize<A, S>: ArrayLength<u8>,
224 {
225 #[doc = "Create a"]
226 #[doc = $obj_desc]
227 #[doc = "object from the given AEAD key and nonce."]
228 pub fn new(key: &Key<A>, nonce: &Nonce<A, S>) -> Self
229 where
230 A: KeyInit,
231 S: NewStream<A>,
232 {
233 Self::from_stream_primitive(S::new(key, nonce))
234 }
235
236 #[doc = "Create a"]
237 #[doc = $obj_desc]
238 #[doc = "object from the given AEAD primitive."]
239 pub fn from_aead(aead: A, nonce: &Nonce<A, S>) -> Self
240 where
241 A: KeyInit,
242 S: NewStream<A>,
243 {
244 Self::from_stream_primitive(S::from_aead(aead, nonce))
245 }
246
247 #[doc = "Create a"]
248 #[doc = $obj_desc]
249 #[doc = "object from the given STREAM primitive."]
250 pub fn from_stream_primitive(stream: S) -> Self {
251 Self {
252 stream,
253 position: Default::default(),
254 }
255 }
256
257 #[doc = "Use the underlying AEAD to"]
258 #[doc = $op_desc]
259 #[doc = "the next AEAD message in this STREAM, returning the"]
260 #[doc = "result as a [`Vec`]."]
261 #[cfg(feature = "alloc")]
262 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
263 pub fn $next_method<'msg, 'aad>(
264 &mut self,
265 payload: impl Into<Payload<'msg, 'aad>>,
266 ) -> Result<Vec<u8>> {
267 if self.position == S::COUNTER_MAX {
268 return Err(Error);
272 }
273
274 let result = self.stream.$op(self.position, false, payload)?;
275
276 self.position += S::COUNTER_INCR;
278 Ok(result)
279 }
280
281 #[doc = "Use the underlying AEAD to"]
282 #[doc = $op_desc]
283 #[doc = "the next AEAD message in this STREAM in-place."]
284 pub fn $next_in_place_method(
285 &mut self,
286 associated_data: &[u8],
287 buffer: &mut dyn Buffer,
288 ) -> Result<()> {
289 if self.position == S::COUNTER_MAX {
290 return Err(Error);
294 }
295
296 self.stream
297 .$in_place_op(self.position, false, associated_data, buffer)?;
298
299 self.position += S::COUNTER_INCR;
301 Ok(())
302 }
303
304 #[doc = "Use the underlying AEAD to"]
305 #[doc = $op_desc]
306 #[doc = "the last AEAD message in this STREAM,"]
307 #[doc = "consuming the "]
308 #[doc = $obj_desc]
309 #[doc = "object in order to prevent further use."]
310 #[cfg(feature = "alloc")]
311 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
312 pub fn $last_method<'msg, 'aad>(
313 self,
314 payload: impl Into<Payload<'msg, 'aad>>,
315 ) -> Result<Vec<u8>> {
316 self.stream.$op(self.position, true, payload)
317 }
318
319 #[doc = "Use the underlying AEAD to"]
320 #[doc = $op_desc]
321 #[doc = "the last AEAD message in this STREAM in-place,"]
322 #[doc = "consuming the "]
323 #[doc = $obj_desc]
324 #[doc = "object in order to prevent further use."]
325 pub fn $last_in_place_method(
326 self,
327 associated_data: &[u8],
328 buffer: &mut dyn Buffer,
329 ) -> Result<()> {
330 self.stream
331 .$in_place_op(self.position, true, associated_data, buffer)
332 }
333 }
334 };
335}
336
337impl_stream_object!(
338 Encryptor,
339 encrypt_next,
340 encrypt_next_in_place,
341 encrypt_last,
342 encrypt_last_in_place,
343 encrypt,
344 encrypt_in_place,
345 "encrypt",
346 "ℰ STREAM encryptor"
347);
348
349impl_stream_object!(
350 Decryptor,
351 decrypt_next,
352 decrypt_next_in_place,
353 decrypt_last,
354 decrypt_last_in_place,
355 decrypt,
356 decrypt_in_place,
357 "decrypt",
358 "𝒟 STREAM decryptor"
359);
360
361pub struct StreamBE32<A>
369where
370 A: AeadInPlace,
371 A::NonceSize: Sub<U5>,
372 <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
373{
374 aead: A,
376
377 nonce: Nonce<A, Self>,
379}
380
381impl<A> NewStream<A> for StreamBE32<A>
382where
383 A: AeadInPlace,
384 A::NonceSize: Sub<U5>,
385 <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
386{
387 fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
388 Self {
389 aead,
390 nonce: nonce.clone(),
391 }
392 }
393}
394
395impl<A> StreamPrimitive<A> for StreamBE32<A>
396where
397 A: AeadInPlace,
398 A::NonceSize: Sub<U5>,
399 <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
400{
401 type NonceOverhead = U5;
402 type Counter = u32;
403 const COUNTER_INCR: u32 = 1;
404 const COUNTER_MAX: u32 = core::u32::MAX;
405
406 fn encrypt_in_place(
407 &self,
408 position: u32,
409 last_block: bool,
410 associated_data: &[u8],
411 buffer: &mut dyn Buffer,
412 ) -> Result<()> {
413 let nonce = self.aead_nonce(position, last_block);
414 self.aead.encrypt_in_place(&nonce, associated_data, buffer)
415 }
416
417 fn decrypt_in_place(
418 &self,
419 position: Self::Counter,
420 last_block: bool,
421 associated_data: &[u8],
422 buffer: &mut dyn Buffer,
423 ) -> Result<()> {
424 let nonce = self.aead_nonce(position, last_block);
425 self.aead.decrypt_in_place(&nonce, associated_data, buffer)
426 }
427}
428
429impl<A> StreamBE32<A>
430where
431 A: AeadInPlace,
432 A::NonceSize: Sub<U5>,
433 <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArrayLength<u8>,
434{
435 fn aead_nonce(&self, position: u32, last_block: bool) -> crate::Nonce<A> {
438 let mut result = GenericArray::default();
439
440 let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
442 prefix.copy_from_slice(&self.nonce);
443
444 let (counter, flag) = tail.split_at_mut(4);
445 counter.copy_from_slice(&position.to_be_bytes());
446 flag[0] = last_block as u8;
447
448 result
449 }
450}
451
452pub struct StreamLE31<A>
458where
459 A: AeadInPlace,
460 A::NonceSize: Sub<U4>,
461 <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
462{
463 aead: A,
465
466 nonce: Nonce<A, Self>,
468}
469
470impl<A> NewStream<A> for StreamLE31<A>
471where
472 A: AeadInPlace,
473 A::NonceSize: Sub<U4>,
474 <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
475{
476 fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
477 Self {
478 aead,
479 nonce: nonce.clone(),
480 }
481 }
482}
483
484impl<A> StreamPrimitive<A> for StreamLE31<A>
485where
486 A: AeadInPlace,
487 A::NonceSize: Sub<U4>,
488 <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
489{
490 type NonceOverhead = U4;
491 type Counter = u32;
492 const COUNTER_INCR: u32 = 1;
493 const COUNTER_MAX: u32 = 0xfff_ffff;
494
495 fn encrypt_in_place(
496 &self,
497 position: u32,
498 last_block: bool,
499 associated_data: &[u8],
500 buffer: &mut dyn Buffer,
501 ) -> Result<()> {
502 let nonce = self.aead_nonce(position, last_block)?;
503 self.aead.encrypt_in_place(&nonce, associated_data, buffer)
504 }
505
506 fn decrypt_in_place(
507 &self,
508 position: Self::Counter,
509 last_block: bool,
510 associated_data: &[u8],
511 buffer: &mut dyn Buffer,
512 ) -> Result<()> {
513 let nonce = self.aead_nonce(position, last_block)?;
514 self.aead.decrypt_in_place(&nonce, associated_data, buffer)
515 }
516}
517
518impl<A> StreamLE31<A>
519where
520 A: AeadInPlace,
521 A::NonceSize: Sub<U4>,
522 <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArrayLength<u8>,
523{
524 fn aead_nonce(&self, position: u32, last_block: bool) -> Result<crate::Nonce<A>> {
527 if position > Self::COUNTER_MAX {
528 return Err(Error);
529 }
530
531 let mut result = GenericArray::default();
532
533 let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
535 prefix.copy_from_slice(&self.nonce);
536
537 let position_with_flag = position | ((last_block as u32) << 31);
538 tail.copy_from_slice(&position_with_flag.to_le_bytes());
539
540 Ok(result)
541 }
542}