Skip to main content

aead_stream/
lib.rs

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