aead/
lib.rs

1//! [Authenticated Encryption with Associated Data] (AEAD) traits
2//!
3//! This crate provides an abstract interface for AEAD ciphers, which guarantee
4//! both confidentiality and integrity, even from a powerful attacker who is
5//! able to execute [chosen-ciphertext attacks]. The resulting security property,
6//! [ciphertext indistinguishability], is considered a basic requirement for
7//! modern cryptographic implementations.
8//!
9//! See [RustCrypto/AEADs] for cipher implementations which use this trait.
10//!
11//! [Authenticated Encryption with Associated Data]: https://en.wikipedia.org/wiki/Authenticated_encryption
12//! [chosen-ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack
13//! [ciphertext indistinguishability]: https://en.wikipedia.org/wiki/Ciphertext_indistinguishability
14//! [RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs
15
16#![no_std]
17#![cfg_attr(docsrs, feature(doc_cfg))]
18#![doc(
19    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
20    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
21)]
22#![forbid(unsafe_code)]
23#![warn(clippy::unwrap_used, missing_docs, rust_2018_idioms)]
24
25#[cfg(feature = "alloc")]
26extern crate alloc;
27
28#[cfg(feature = "std")]
29extern crate std;
30
31#[cfg(feature = "dev")]
32#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
33pub mod dev;
34
35#[cfg(feature = "stream")]
36#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
37pub mod stream;
38
39pub use crypto_common::{Key, KeyInit, KeySizeUser};
40pub use generic_array::{self, typenum::consts};
41
42#[cfg(feature = "arrayvec")]
43#[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))]
44pub use arrayvec;
45
46#[cfg(feature = "bytes")]
47#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
48pub use bytes;
49
50#[cfg(feature = "getrandom")]
51#[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
52pub use crypto_common::rand_core::OsRng;
53
54#[cfg(feature = "heapless")]
55#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
56pub use heapless;
57
58#[cfg(feature = "rand_core")]
59#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
60pub use crypto_common::rand_core;
61
62use core::fmt;
63use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
64
65#[cfg(feature = "alloc")]
66use alloc::vec::Vec;
67
68#[cfg(feature = "bytes")]
69use bytes::BytesMut;
70
71#[cfg(feature = "rand_core")]
72use rand_core::{CryptoRng, RngCore};
73
74/// Error type.
75///
76/// This type is deliberately opaque as to avoid potential side-channel
77/// leakage (e.g. padding oracle).
78#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
79pub struct Error;
80
81/// Result type alias with [`Error`].
82pub type Result<T> = core::result::Result<T, Error>;
83
84impl fmt::Display for Error {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        f.write_str("aead::Error")
87    }
88}
89
90#[cfg(feature = "std")]
91impl std::error::Error for Error {}
92
93/// Nonce: single-use value for ensuring ciphertexts are unique
94pub type Nonce<A> = GenericArray<u8, <A as AeadCore>::NonceSize>;
95
96/// Tag: authentication code which ensures ciphertexts are authentic
97pub type Tag<A> = GenericArray<u8, <A as AeadCore>::TagSize>;
98
99/// Authenticated Encryption with Associated Data (AEAD) algorithm core trait.
100///
101/// Defines nonce, tag, and overhead sizes that are consumed by various other
102/// `Aead*` traits.
103pub trait AeadCore {
104    /// The length of a nonce.
105    type NonceSize: ArrayLength<u8>;
106
107    /// The maximum length of the nonce.
108    type TagSize: ArrayLength<u8>;
109
110    /// The upper bound amount of additional space required to support a
111    /// ciphertext vs. a plaintext.
112    type CiphertextOverhead: ArrayLength<u8> + Unsigned;
113
114    /// Generate a random nonce for this AEAD algorithm.
115    ///
116    /// AEAD algorithms accept a parameter to encryption/decryption called
117    /// a "nonce" which must be unique every time encryption is performed and
118    /// never repeated for the same key. The nonce is often prepended to the
119    /// ciphertext. The nonce used to produce a given ciphertext must be passed
120    /// to the decryption function in order for it to decrypt correctly.
121    ///
122    /// Nonces don't necessarily have to be random, but it is one strategy
123    /// which is implemented by this function.
124    ///
125    /// # ⚠️Security Warning
126    ///
127    /// AEAD algorithms often fail catastrophically if nonces are ever repeated
128    /// (with SIV modes being an exception).
129    ///
130    /// Using random nonces runs the risk of repeating them unless the nonce
131    /// size is particularly large (e.g. 192-bit extended nonces used by the
132    /// `XChaCha20Poly1305` and `XSalsa20Poly1305` constructions.
133    ///
134    /// [NIST SP 800-38D] recommends the following:
135    ///
136    /// > The total number of invocations of the authenticated encryption
137    /// > function shall not exceed 2^32, including all IV lengths and all
138    /// > instances of the authenticated encryption function with the given key.
139    ///
140    /// Following this guideline, only 4,294,967,296 messages with random
141    /// nonces can be encrypted under a given key. While this bound is high,
142    /// it's possible to encounter in practice, and systems which might
143    /// reach it should consider alternatives to purely random nonces, like
144    /// a counter or a combination of a random nonce + counter.
145    ///
146    /// See the [`stream`] module for a ready-made implementation of the latter.
147    ///
148    /// [NIST SP 800-38D]: https://csrc.nist.gov/publications/detail/sp/800-38d/final
149    #[cfg(feature = "rand_core")]
150    #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
151    fn generate_nonce(mut rng: impl CryptoRng + RngCore) -> Nonce<Self>
152    where
153        Nonce<Self>: Default,
154    {
155        let mut nonce = Nonce::<Self>::default();
156        rng.fill_bytes(&mut nonce);
157        nonce
158    }
159}
160
161/// Authenticated Encryption with Associated Data (AEAD) algorithm.
162///
163/// This trait is intended for use with stateless AEAD algorithms. The
164/// [`AeadMut`] trait provides a stateful interface.
165#[cfg(feature = "alloc")]
166#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
167pub trait Aead: AeadCore {
168    /// Encrypt the given plaintext payload, and return the resulting
169    /// ciphertext as a vector of bytes.
170    ///
171    /// The [`Payload`] type can be used to provide Additional Associated Data
172    /// (AAD) along with the message: this is an optional bytestring which is
173    /// not encrypted, but *is* authenticated along with the message. Failure
174    /// to pass the same AAD that was used during encryption will cause
175    /// decryption to fail, which is useful if you would like to "bind" the
176    /// ciphertext to some other identifier, like a digital signature key
177    /// or other identifier.
178    ///
179    /// If you don't care about AAD and just want to encrypt a plaintext
180    /// message, `&[u8]` will automatically be coerced into a `Payload`:
181    ///
182    /// ```nobuild
183    /// let plaintext = b"Top secret message, handle with care";
184    /// let ciphertext = cipher.encrypt(nonce, plaintext);
185    /// ```
186    ///
187    /// The default implementation assumes a postfix tag (ala AES-GCM,
188    /// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not
189    /// use a postfix tag will need to override this to correctly assemble the
190    /// ciphertext message.
191    fn encrypt<'msg, 'aad>(
192        &self,
193        nonce: &Nonce<Self>,
194        plaintext: impl Into<Payload<'msg, 'aad>>,
195    ) -> Result<Vec<u8>>;
196
197    /// Decrypt the given ciphertext slice, and return the resulting plaintext
198    /// as a vector of bytes.
199    ///
200    /// See notes on [`Aead::encrypt()`] about allowable message payloads and
201    /// Associated Additional Data (AAD).
202    ///
203    /// If you have no AAD, you can call this as follows:
204    ///
205    /// ```nobuild
206    /// let ciphertext = b"...";
207    /// let plaintext = cipher.decrypt(nonce, ciphertext)?;
208    /// ```
209    ///
210    /// The default implementation assumes a postfix tag (ala AES-GCM,
211    /// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not
212    /// use a postfix tag will need to override this to correctly parse the
213    /// ciphertext message.
214    fn decrypt<'msg, 'aad>(
215        &self,
216        nonce: &Nonce<Self>,
217        ciphertext: impl Into<Payload<'msg, 'aad>>,
218    ) -> Result<Vec<u8>>;
219}
220
221/// Stateful Authenticated Encryption with Associated Data algorithm.
222#[cfg(feature = "alloc")]
223#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
224pub trait AeadMut: AeadCore {
225    /// Encrypt the given plaintext slice, and return the resulting ciphertext
226    /// as a vector of bytes.
227    ///
228    /// See notes on [`Aead::encrypt()`] about allowable message payloads and
229    /// Associated Additional Data (AAD).
230    fn encrypt<'msg, 'aad>(
231        &mut self,
232        nonce: &Nonce<Self>,
233        plaintext: impl Into<Payload<'msg, 'aad>>,
234    ) -> Result<Vec<u8>>;
235
236    /// Decrypt the given ciphertext slice, and return the resulting plaintext
237    /// as a vector of bytes.
238    ///
239    /// See notes on [`Aead::encrypt()`] and [`Aead::decrypt()`] about allowable
240    /// message payloads and Associated Additional Data (AAD).
241    fn decrypt<'msg, 'aad>(
242        &mut self,
243        nonce: &Nonce<Self>,
244        ciphertext: impl Into<Payload<'msg, 'aad>>,
245    ) -> Result<Vec<u8>>;
246}
247
248/// Implement the `decrypt_in_place` method on [`AeadInPlace`] and
249/// [`AeadMutInPlace]`, using a macro to gloss over the `&self` vs `&mut self`.
250///
251/// Assumes a postfix authentication tag. AEAD ciphers which do not use a
252/// postfix authentication tag will need to define their own implementation.
253macro_rules! impl_decrypt_in_place {
254    ($aead:expr, $nonce:expr, $aad:expr, $buffer:expr) => {{
255        if $buffer.len() < Self::TagSize::to_usize() {
256            return Err(Error);
257        }
258
259        let tag_pos = $buffer.len() - Self::TagSize::to_usize();
260        let (msg, tag) = $buffer.as_mut().split_at_mut(tag_pos);
261        $aead.decrypt_in_place_detached($nonce, $aad, msg, Tag::<Self>::from_slice(tag))?;
262        $buffer.truncate(tag_pos);
263        Ok(())
264    }};
265}
266
267/// In-place stateless AEAD trait.
268///
269/// This trait is both object safe and has no dependencies on `alloc` or `std`.
270pub trait AeadInPlace: AeadCore {
271    /// Encrypt the given buffer containing a plaintext message in-place.
272    ///
273    /// The buffer must have sufficient capacity to store the ciphertext
274    /// message, which will always be larger than the original plaintext.
275    /// The exact size needed is cipher-dependent, but generally includes
276    /// the size of an authentication tag.
277    ///
278    /// Returns an error if the buffer has insufficient capacity to store the
279    /// resulting ciphertext message.
280    fn encrypt_in_place(
281        &self,
282        nonce: &Nonce<Self>,
283        associated_data: &[u8],
284        buffer: &mut dyn Buffer,
285    ) -> Result<()> {
286        let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?;
287        buffer.extend_from_slice(tag.as_slice())?;
288        Ok(())
289    }
290
291    /// Encrypt the data in-place, returning the authentication tag
292    fn encrypt_in_place_detached(
293        &self,
294        nonce: &Nonce<Self>,
295        associated_data: &[u8],
296        buffer: &mut [u8],
297    ) -> Result<Tag<Self>>;
298
299    /// Decrypt the message in-place, returning an error in the event the
300    /// provided authentication tag does not match the given ciphertext.
301    ///
302    /// The buffer will be truncated to the length of the original plaintext
303    /// message upon success.
304    fn decrypt_in_place(
305        &self,
306        nonce: &Nonce<Self>,
307        associated_data: &[u8],
308        buffer: &mut dyn Buffer,
309    ) -> Result<()> {
310        impl_decrypt_in_place!(self, nonce, associated_data, buffer)
311    }
312
313    /// Decrypt the message in-place, returning an error in the event the provided
314    /// authentication tag does not match the given ciphertext (i.e. ciphertext
315    /// is modified/unauthentic)
316    fn decrypt_in_place_detached(
317        &self,
318        nonce: &Nonce<Self>,
319        associated_data: &[u8],
320        buffer: &mut [u8],
321        tag: &Tag<Self>,
322    ) -> Result<()>;
323}
324
325/// In-place stateful AEAD trait.
326///
327/// This trait is both object safe and has no dependencies on `alloc` or `std`.
328pub trait AeadMutInPlace: AeadCore {
329    /// Encrypt the given buffer containing a plaintext message in-place.
330    ///
331    /// The buffer must have sufficient capacity to store the ciphertext
332    /// message, which will always be larger than the original plaintext.
333    /// The exact size needed is cipher-dependent, but generally includes
334    /// the size of an authentication tag.
335    ///
336    /// Returns an error if the buffer has insufficient capacity to store the
337    /// resulting ciphertext message.
338    fn encrypt_in_place(
339        &mut self,
340        nonce: &Nonce<Self>,
341        associated_data: &[u8],
342        buffer: &mut impl Buffer,
343    ) -> Result<()> {
344        let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?;
345        buffer.extend_from_slice(tag.as_slice())?;
346        Ok(())
347    }
348
349    /// Encrypt the data in-place, returning the authentication tag
350    fn encrypt_in_place_detached(
351        &mut self,
352        nonce: &Nonce<Self>,
353        associated_data: &[u8],
354        buffer: &mut [u8],
355    ) -> Result<Tag<Self>>;
356
357    /// Decrypt the message in-place, returning an error in the event the
358    /// provided authentication tag does not match the given ciphertext.
359    ///
360    /// The buffer will be truncated to the length of the original plaintext
361    /// message upon success.
362    fn decrypt_in_place(
363        &mut self,
364        nonce: &Nonce<Self>,
365        associated_data: &[u8],
366        buffer: &mut impl Buffer,
367    ) -> Result<()> {
368        impl_decrypt_in_place!(self, nonce, associated_data, buffer)
369    }
370
371    /// Decrypt the data in-place, returning an error in the event the provided
372    /// authentication tag does not match the given ciphertext (i.e. ciphertext
373    /// is modified/unauthentic)
374    fn decrypt_in_place_detached(
375        &mut self,
376        nonce: &Nonce<Self>,
377        associated_data: &[u8],
378        buffer: &mut [u8],
379        tag: &Tag<Self>,
380    ) -> Result<()>;
381}
382
383#[cfg(feature = "alloc")]
384impl<Alg: AeadInPlace> Aead for Alg {
385    fn encrypt<'msg, 'aad>(
386        &self,
387        nonce: &Nonce<Self>,
388        plaintext: impl Into<Payload<'msg, 'aad>>,
389    ) -> Result<Vec<u8>> {
390        let payload = plaintext.into();
391        let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
392        buffer.extend_from_slice(payload.msg);
393        self.encrypt_in_place(nonce, payload.aad, &mut buffer)?;
394        Ok(buffer)
395    }
396
397    fn decrypt<'msg, 'aad>(
398        &self,
399        nonce: &Nonce<Self>,
400        ciphertext: impl Into<Payload<'msg, 'aad>>,
401    ) -> Result<Vec<u8>> {
402        let payload = ciphertext.into();
403        let mut buffer = Vec::from(payload.msg);
404        self.decrypt_in_place(nonce, payload.aad, &mut buffer)?;
405        Ok(buffer)
406    }
407}
408
409#[cfg(feature = "alloc")]
410impl<Alg: AeadMutInPlace> AeadMut for Alg {
411    fn encrypt<'msg, 'aad>(
412        &mut self,
413        nonce: &Nonce<Self>,
414        plaintext: impl Into<Payload<'msg, 'aad>>,
415    ) -> Result<Vec<u8>> {
416        let payload = plaintext.into();
417        let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
418        buffer.extend_from_slice(payload.msg);
419        self.encrypt_in_place(nonce, payload.aad, &mut buffer)?;
420        Ok(buffer)
421    }
422
423    fn decrypt<'msg, 'aad>(
424        &mut self,
425        nonce: &Nonce<Self>,
426        ciphertext: impl Into<Payload<'msg, 'aad>>,
427    ) -> Result<Vec<u8>> {
428        let payload = ciphertext.into();
429        let mut buffer = Vec::from(payload.msg);
430        self.decrypt_in_place(nonce, payload.aad, &mut buffer)?;
431        Ok(buffer)
432    }
433}
434
435impl<Alg: AeadInPlace> AeadMutInPlace for Alg {
436    fn encrypt_in_place(
437        &mut self,
438        nonce: &Nonce<Self>,
439        associated_data: &[u8],
440        buffer: &mut impl Buffer,
441    ) -> Result<()> {
442        <Self as AeadInPlace>::encrypt_in_place(self, nonce, associated_data, buffer)
443    }
444
445    fn encrypt_in_place_detached(
446        &mut self,
447        nonce: &Nonce<Self>,
448        associated_data: &[u8],
449        buffer: &mut [u8],
450    ) -> Result<Tag<Self>> {
451        <Self as AeadInPlace>::encrypt_in_place_detached(self, nonce, associated_data, buffer)
452    }
453
454    fn decrypt_in_place(
455        &mut self,
456        nonce: &Nonce<Self>,
457        associated_data: &[u8],
458        buffer: &mut impl Buffer,
459    ) -> Result<()> {
460        <Self as AeadInPlace>::decrypt_in_place(self, nonce, associated_data, buffer)
461    }
462
463    fn decrypt_in_place_detached(
464        &mut self,
465        nonce: &Nonce<Self>,
466        associated_data: &[u8],
467        buffer: &mut [u8],
468        tag: &Tag<Self>,
469    ) -> Result<()> {
470        <Self as AeadInPlace>::decrypt_in_place_detached(self, nonce, associated_data, buffer, tag)
471    }
472}
473
474/// AEAD payloads (message + AAD).
475///
476/// Combination of a message (plaintext or ciphertext) and
477/// "additional associated data" (AAD) to be authenticated (in cleartext)
478/// along with the message.
479///
480/// If you don't care about AAD, you can pass a `&[u8]` as the payload to
481/// `encrypt`/`decrypt` and it will automatically be coerced to this type.
482#[cfg(feature = "alloc")]
483#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
484pub struct Payload<'msg, 'aad> {
485    /// Message to be encrypted/decrypted
486    pub msg: &'msg [u8],
487
488    /// Optional "additional associated data" to authenticate along with
489    /// this message. If AAD is provided at the time the message is encrypted,
490    /// the same AAD *MUST* be provided at the time the message is decrypted,
491    /// or decryption will fail.
492    pub aad: &'aad [u8],
493}
494
495#[cfg(feature = "alloc")]
496impl<'msg, 'aad> From<&'msg [u8]> for Payload<'msg, 'aad> {
497    fn from(msg: &'msg [u8]) -> Self {
498        Self { msg, aad: b"" }
499    }
500}
501
502/// In-place encryption/decryption byte buffers.
503///
504/// This trait defines the set of methods needed to support in-place operations
505/// on a `Vec`-like data type.
506pub trait Buffer: AsRef<[u8]> + AsMut<[u8]> {
507    /// Get the length of the buffer
508    fn len(&self) -> usize {
509        self.as_ref().len()
510    }
511
512    /// Is the buffer empty?
513    fn is_empty(&self) -> bool {
514        self.as_ref().is_empty()
515    }
516
517    /// Extend this buffer from the given slice
518    fn extend_from_slice(&mut self, other: &[u8]) -> Result<()>;
519
520    /// Truncate this buffer to the given size
521    fn truncate(&mut self, len: usize);
522}
523
524#[cfg(feature = "alloc")]
525impl Buffer for Vec<u8> {
526    fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
527        Vec::extend_from_slice(self, other);
528        Ok(())
529    }
530
531    fn truncate(&mut self, len: usize) {
532        Vec::truncate(self, len);
533    }
534}
535
536#[cfg(feature = "bytes")]
537impl Buffer for BytesMut {
538    fn len(&self) -> usize {
539        BytesMut::len(self)
540    }
541
542    fn is_empty(&self) -> bool {
543        BytesMut::is_empty(self)
544    }
545
546    fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
547        BytesMut::extend_from_slice(self, other);
548        Ok(())
549    }
550
551    fn truncate(&mut self, len: usize) {
552        BytesMut::truncate(self, len);
553    }
554}
555
556#[cfg(feature = "arrayvec")]
557impl<const N: usize> Buffer for arrayvec::ArrayVec<u8, N> {
558    fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
559        arrayvec::ArrayVec::try_extend_from_slice(self, other).map_err(|_| Error)
560    }
561
562    fn truncate(&mut self, len: usize) {
563        arrayvec::ArrayVec::truncate(self, len);
564    }
565}
566
567#[cfg(feature = "heapless")]
568impl<const N: usize> Buffer for heapless::Vec<u8, N> {
569    fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> {
570        heapless::Vec::extend_from_slice(self, other).map_err(|_| Error)
571    }
572
573    fn truncate(&mut self, len: usize) {
574        heapless::Vec::truncate(self, len);
575    }
576}
577
578#[cfg(test)]
579mod tests {
580    use super::*;
581
582    /// Ensure that `AeadInPlace` is object-safe
583    #[allow(dead_code)]
584    type DynAeadInPlace<N, T, O> =
585        dyn AeadInPlace<NonceSize = N, TagSize = T, CiphertextOverhead = O>;
586
587    /// Ensure that `AeadMutInPlace` is object-safe
588    #[allow(dead_code)]
589    type DynAeadMutInPlace<N, T, O> =
590        dyn AeadMutInPlace<NonceSize = N, TagSize = T, CiphertextOverhead = O>;
591}