Skip to main content

aead_stream/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![allow(clippy::upper_case_acronyms)]
9
10#[cfg(feature = "alloc")]
11extern crate alloc;
12
13use aead::{
14    AeadCore, AeadInOut, Buffer, Error, Result,
15    array::{
16        Array, ArraySize,
17        typenum::{U4, U5, Unsigned},
18    },
19};
20use core::ops::{AddAssign, Sub};
21
22pub use aead;
23
24pub use aead::{Key, KeyInit};
25
26#[cfg(feature = "alloc")]
27use {aead::Payload, alloc::vec::Vec};
28
29/// Nonce as used by a given AEAD construction and STREAM primitive.
30pub type Nonce<A, S> = Array<u8, NonceSize<A, S>>;
31
32/// Size of a nonce as used by a STREAM construction, sans the overhead of
33/// the STREAM protocol itself.
34pub type NonceSize<A, S> =
35    <<A as AeadCore>::NonceSize as Sub<<S as StreamPrimitive<A>>::NonceOverhead>>::Output;
36
37/// Create a new STREAM from the provided AEAD.
38pub trait NewStream<A>: StreamPrimitive<A>
39where
40    A: AeadInOut,
41    A::NonceSize: Sub<Self::NonceOverhead>,
42    NonceSize<A, Self>: ArraySize,
43{
44    /// Create a new STREAM with the given key and nonce.
45    fn new(key: &Key<A>, nonce: &Nonce<A, Self>) -> Self
46    where
47        A: KeyInit,
48        Self: Sized,
49    {
50        Self::from_aead(A::new(key), nonce)
51    }
52
53    /// Create a new STREAM from the given AEAD cipher.
54    fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self;
55}
56
57/// Low-level STREAM implementation.
58///
59/// This trait provides a particular "flavor" of STREAM, as there are
60/// different ways the specifics of the construction can be implemented.
61///
62/// Deliberately immutable and stateless to permit parallel operation.
63pub trait StreamPrimitive<A>
64where
65    A: AeadInOut,
66    A::NonceSize: Sub<Self::NonceOverhead>,
67    NonceSize<A, Self>: ArraySize,
68{
69    /// Number of bytes this STREAM primitive requires from the nonce.
70    type NonceOverhead: ArraySize;
71
72    /// Type used as the STREAM counter.
73    type Counter: AddAssign + Copy + Default + Eq;
74
75    /// Value to use when incrementing the STREAM counter (i.e. one)
76    const COUNTER_INCR: Self::Counter;
77
78    /// Maximum value of the STREAM counter.
79    const COUNTER_MAX: Self::Counter;
80
81    /// Encrypt an AEAD message in-place at the given position in the STREAM.
82    ///
83    /// # Errors
84    /// Propagates errors from the underlying AEAD.
85    fn encrypt_in_place(
86        &self,
87        position: Self::Counter,
88        last_block: bool,
89        associated_data: &[u8],
90        buffer: &mut dyn Buffer,
91    ) -> Result<()>;
92
93    /// Decrypt an AEAD message in-place at the given position in the STREAM.
94    ///
95    /// # Errors
96    /// Propagates errors from the underlying AEAD.
97    fn decrypt_in_place(
98        &self,
99        position: Self::Counter,
100        last_block: bool,
101        associated_data: &[u8],
102        buffer: &mut dyn Buffer,
103    ) -> Result<()>;
104
105    /// Encrypt the given plaintext payload, and return the resulting ciphertext as a byte vector.
106    ///
107    /// # Errors
108    /// Propagates errors from the underlying AEAD.
109    #[cfg(feature = "alloc")]
110    fn encrypt<'msg, 'aad>(
111        &self,
112        position: Self::Counter,
113        last_block: bool,
114        plaintext: impl Into<Payload<'msg, 'aad>>,
115    ) -> Result<Vec<u8>> {
116        let payload = plaintext.into();
117        let mut buffer = Vec::with_capacity(payload.msg.len() + A::TagSize::to_usize());
118        buffer.extend_from_slice(payload.msg);
119        self.encrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
120        Ok(buffer)
121    }
122
123    /// Decrypt the given ciphertext slice, and return the resulting plaintext as a byte vector.
124    ///
125    /// # Errors
126    /// Propagates errors from the underlying AEAD.
127    #[cfg(feature = "alloc")]
128    fn decrypt<'msg, 'aad>(
129        &self,
130        position: Self::Counter,
131        last_block: bool,
132        ciphertext: impl Into<Payload<'msg, 'aad>>,
133    ) -> Result<Vec<u8>> {
134        let payload = ciphertext.into();
135        let mut buffer = Vec::from(payload.msg);
136        self.decrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
137        Ok(buffer)
138    }
139
140    /// Obtain [`Encryptor`] for this [`StreamPrimitive`].
141    fn encryptor(self) -> Encryptor<A, Self>
142    where
143        Self: Sized,
144    {
145        Encryptor::from_stream_primitive(self)
146    }
147
148    /// Obtain [`Decryptor`] for this [`StreamPrimitive`].
149    fn decryptor(self) -> Decryptor<A, Self>
150    where
151        Self: Sized,
152    {
153        Decryptor::from_stream_primitive(self)
154    }
155}
156
157/// Implement a stateful STREAM object (i.e. encryptor or decryptor)
158macro_rules! impl_stream_object {
159    (
160        $name:ident,
161        $next_method:tt,
162        $next_in_place_method:tt,
163        $last_method:tt,
164        $last_in_place_method:tt,
165        $op:tt,
166        $in_place_op:tt,
167        $op_desc:expr,
168        $obj_desc:expr
169    ) => {
170        #[doc = "Stateful STREAM object which can"]
171        #[doc = $op_desc]
172        #[doc = "AEAD messages one-at-a-time."]
173        #[doc = ""]
174        #[doc = "This corresponds to the "]
175        #[doc = $obj_desc]
176        #[doc = "object as defined in the paper"]
177        #[doc = "[Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]."]
178        #[doc = ""]
179        #[doc = "[1]: https://eprint.iacr.org/2015/189.pdf"]
180        #[derive(Debug)]
181        pub struct $name<A, S>
182        where
183            A: AeadInOut,
184            S: StreamPrimitive<A>,
185            A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
186            NonceSize<A, S>: ArraySize,
187        {
188            /// Underlying STREAM primitive.
189            stream: S,
190
191            /// Current position in the STREAM.
192            position: S::Counter,
193        }
194
195        impl<A, S> $name<A, S>
196        where
197            A: AeadInOut,
198            S: StreamPrimitive<A>,
199            A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
200            NonceSize<A, S>: ArraySize,
201        {
202            #[doc = "Create a"]
203            #[doc = $obj_desc]
204            #[doc = "object from the given AEAD key and nonce."]
205            pub fn new(key: &Key<A>, nonce: &Nonce<A, S>) -> Self
206            where
207                A: KeyInit,
208                S: NewStream<A>,
209            {
210                Self::from_stream_primitive(S::new(key, nonce))
211            }
212
213            #[doc = "Create a"]
214            #[doc = $obj_desc]
215            #[doc = "object from the given AEAD primitive."]
216            pub fn from_aead(aead: A, nonce: &Nonce<A, S>) -> Self
217            where
218                S: NewStream<A>,
219            {
220                Self::from_stream_primitive(S::from_aead(aead, nonce))
221            }
222
223            #[doc = "Create a"]
224            #[doc = $obj_desc]
225            #[doc = "object from the given STREAM primitive."]
226            pub fn from_stream_primitive(stream: S) -> Self {
227                Self {
228                    stream,
229                    position: Default::default(),
230                }
231            }
232
233            #[doc = "Use the underlying AEAD to"]
234            #[doc = $op_desc]
235            #[doc = "the next AEAD message in this STREAM, returning the"]
236            #[doc = "result as a [`Vec`]."]
237            #[doc = "\n"]
238            #[doc = "# Errors\n"]
239            #[doc = "Propagates errors from the underlying AEAD"]
240            #[cfg(feature = "alloc")]
241            pub fn $next_method<'msg, 'aad>(
242                &mut self,
243                payload: impl Into<Payload<'msg, 'aad>>,
244            ) -> Result<Vec<u8>> {
245                if self.position == S::COUNTER_MAX {
246                    // Counter overflow. Note that the maximum counter value is
247                    // deliberately disallowed, as it would preclude being able
248                    // to encrypt a last block (i.e. with `$last_in_place_method`)
249                    return Err(Error);
250                }
251
252                let result = self.stream.$op(self.position, false, payload)?;
253
254                // Note: overflow checked above
255                self.position += S::COUNTER_INCR;
256                Ok(result)
257            }
258
259            #[doc = "Use the underlying AEAD to"]
260            #[doc = $op_desc]
261            #[doc = "the next AEAD message in this STREAM in-place."]
262            #[doc = "\n"]
263            #[doc = "# Errors\n"]
264            #[doc = "Propagates errors from the underlying AEAD"]
265            pub fn $next_in_place_method(
266                &mut self,
267                associated_data: &[u8],
268                buffer: &mut dyn Buffer,
269            ) -> Result<()> {
270                if self.position == S::COUNTER_MAX {
271                    // Counter overflow. Note that the maximum counter value is
272                    // deliberately disallowed, as it would preclude being able
273                    // to encrypt a last block (i.e. with `$last_in_place_method`)
274                    return Err(Error);
275                }
276
277                self.stream
278                    .$in_place_op(self.position, false, associated_data, buffer)?;
279
280                // Note: overflow checked above
281                self.position += S::COUNTER_INCR;
282                Ok(())
283            }
284
285            #[doc = "Use the underlying AEAD to"]
286            #[doc = $op_desc]
287            #[doc = "the last AEAD message in this STREAM,"]
288            #[doc = "consuming the "]
289            #[doc = $obj_desc]
290            #[doc = "object in order to prevent further use."]
291            #[doc = "\n"]
292            #[doc = "# Errors\n"]
293            #[doc = "Propagates errors from the underlying AEAD"]
294            #[cfg(feature = "alloc")]
295            pub fn $last_method<'msg, 'aad>(
296                self,
297                payload: impl Into<Payload<'msg, 'aad>>,
298            ) -> Result<Vec<u8>> {
299                self.stream.$op(self.position, true, payload)
300            }
301
302            #[doc = "Use the underlying AEAD to"]
303            #[doc = $op_desc]
304            #[doc = "the last AEAD message in this STREAM in-place,"]
305            #[doc = "consuming the "]
306            #[doc = $obj_desc]
307            #[doc = "object in order to prevent further use."]
308            #[doc = "\n"]
309            #[doc = "# Errors\n"]
310            #[doc = "Propagates errors from the underlying AEAD"]
311            pub fn $last_in_place_method(
312                self,
313                associated_data: &[u8],
314                buffer: &mut dyn Buffer,
315            ) -> Result<()> {
316                self.stream
317                    .$in_place_op(self.position, true, associated_data, buffer)
318            }
319        }
320    };
321}
322
323impl_stream_object!(
324    Encryptor,
325    encrypt_next,
326    encrypt_next_in_place,
327    encrypt_last,
328    encrypt_last_in_place,
329    encrypt,
330    encrypt_in_place,
331    "encrypt",
332    "ℰ STREAM encryptor"
333);
334
335impl_stream_object!(
336    Decryptor,
337    decrypt_next,
338    decrypt_next_in_place,
339    decrypt_last,
340    decrypt_last_in_place,
341    decrypt,
342    decrypt_in_place,
343    "decrypt",
344    "𝒟 STREAM decryptor"
345);
346
347/// STREAM encryptor instantiated with [`StreamBE32`] as the underlying
348/// STREAM primitive.
349pub type EncryptorBE32<A> = Encryptor<A, StreamBE32<A>>;
350
351/// STREAM decryptor instantiated with [`StreamBE32`] as the underlying
352/// STREAM primitive.
353pub type DecryptorBE32<A> = Decryptor<A, StreamBE32<A>>;
354
355/// STREAM encryptor instantiated with [`StreamLE31`] as the underlying
356/// STREAM primitive.
357pub type EncryptorLE31<A> = Encryptor<A, StreamLE31<A>>;
358
359/// STREAM decryptor instantiated with [`StreamLE31`] as the underlying
360/// STREAM primitive.
361pub type DecryptorLE31<A> = Decryptor<A, StreamLE31<A>>;
362
363/// The original "Rogaway-flavored" STREAM as described in the paper
364/// [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1].
365///
366/// Uses a 32-bit big endian counter and 1-byte "last block" flag stored as
367/// the last 5-bytes of the AEAD nonce.
368///
369/// [1]: https://eprint.iacr.org/2015/189.pdf
370#[derive(Debug)]
371pub struct StreamBE32<A>
372where
373    A: AeadInOut,
374    A::NonceSize: Sub<U5>,
375    <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArraySize,
376{
377    /// Underlying AEAD cipher
378    aead: A,
379
380    /// Nonce (sans STREAM overhead)
381    nonce: Nonce<A, Self>,
382}
383
384impl<A> NewStream<A> for StreamBE32<A>
385where
386    A: AeadInOut,
387    A::NonceSize: Sub<U5>,
388    <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArraySize,
389{
390    fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
391        Self {
392            aead,
393            nonce: nonce.clone(),
394        }
395    }
396}
397
398impl<A> StreamPrimitive<A> for StreamBE32<A>
399where
400    A: AeadInOut,
401    A::NonceSize: Sub<U5>,
402    <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArraySize,
403{
404    type NonceOverhead = U5;
405    type Counter = u32;
406    const COUNTER_INCR: u32 = 1;
407    const COUNTER_MAX: u32 = u32::MAX;
408
409    fn encrypt_in_place(
410        &self,
411        position: u32,
412        last_block: bool,
413        associated_data: &[u8],
414        buffer: &mut dyn Buffer,
415    ) -> Result<()> {
416        let nonce = self.aead_nonce(position, last_block);
417        self.aead.encrypt_in_place(&nonce, associated_data, buffer)
418    }
419
420    fn decrypt_in_place(
421        &self,
422        position: Self::Counter,
423        last_block: bool,
424        associated_data: &[u8],
425        buffer: &mut dyn Buffer,
426    ) -> Result<()> {
427        let nonce = self.aead_nonce(position, last_block);
428        self.aead.decrypt_in_place(&nonce, associated_data, buffer)
429    }
430}
431
432impl<A> StreamBE32<A>
433where
434    A: AeadInOut,
435    A::NonceSize: Sub<U5>,
436    <<A as AeadCore>::NonceSize as Sub<U5>>::Output: ArraySize,
437{
438    /// Compute the full AEAD nonce including the STREAM counter and last
439    /// block flag.
440    fn aead_nonce(&self, position: u32, last_block: bool) -> aead::Nonce<A> {
441        let mut result = Array::default();
442
443        // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics)
444        let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
445        prefix.copy_from_slice(&self.nonce);
446
447        let (counter, flag) = tail.split_at_mut(4);
448        counter.copy_from_slice(&position.to_be_bytes());
449        flag[0] = u8::from(last_block);
450
451        result
452    }
453}
454
455/// STREAM as instantiated with a 31-bit little endian counter and 1-bit
456/// "last block" flag stored as the most significant bit of the counter
457/// when interpreted as a 32-bit integer.
458///
459/// The 31-bit + 1-bit value is stored as the last 4 bytes of the AEAD nonce.
460#[derive(Debug)]
461pub struct StreamLE31<A>
462where
463    A: AeadInOut,
464    A::NonceSize: Sub<U4>,
465    <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArraySize,
466{
467    /// Underlying AEAD cipher
468    aead: A,
469
470    /// Nonce (sans STREAM overhead)
471    nonce: Nonce<A, Self>,
472}
473
474impl<A> NewStream<A> for StreamLE31<A>
475where
476    A: AeadInOut,
477    A::NonceSize: Sub<U4>,
478    <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArraySize,
479{
480    fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self {
481        Self {
482            aead,
483            nonce: nonce.clone(),
484        }
485    }
486}
487
488impl<A> StreamPrimitive<A> for StreamLE31<A>
489where
490    A: AeadInOut,
491    A::NonceSize: Sub<U4>,
492    <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArraySize,
493{
494    type NonceOverhead = U4;
495    type Counter = u32;
496    const COUNTER_INCR: u32 = 1;
497    const COUNTER_MAX: u32 = 0x7fff_ffff;
498
499    fn encrypt_in_place(
500        &self,
501        position: u32,
502        last_block: bool,
503        associated_data: &[u8],
504        buffer: &mut dyn Buffer,
505    ) -> Result<()> {
506        let nonce = self.aead_nonce(position, last_block)?;
507        self.aead.encrypt_in_place(&nonce, associated_data, buffer)
508    }
509
510    fn decrypt_in_place(
511        &self,
512        position: Self::Counter,
513        last_block: bool,
514        associated_data: &[u8],
515        buffer: &mut dyn Buffer,
516    ) -> Result<()> {
517        let nonce = self.aead_nonce(position, last_block)?;
518        self.aead.decrypt_in_place(&nonce, associated_data, buffer)
519    }
520}
521
522impl<A> StreamLE31<A>
523where
524    A: AeadInOut,
525    A::NonceSize: Sub<U4>,
526    <<A as AeadCore>::NonceSize as Sub<U4>>::Output: ArraySize,
527{
528    /// Compute the full AEAD nonce including the STREAM counter and last
529    /// block flag.
530    fn aead_nonce(&self, position: u32, last_block: bool) -> Result<aead::Nonce<A>> {
531        if position > Self::COUNTER_MAX {
532            return Err(Error);
533        }
534
535        let mut result = Array::default();
536
537        // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics)
538        let (prefix, tail) = result.split_at_mut(NonceSize::<A, Self>::to_usize());
539        prefix.copy_from_slice(&self.nonce);
540
541        let position_with_flag = position | (u32::from(last_block) << 31);
542        tail.copy_from_slice(&position_with_flag.to_le_bytes());
543
544        Ok(result)
545    }
546}