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}