wolf_crypto/aead/chacha20_poly1305.rs
1//! The `ChaCha20Poly1305` Authenticated Encryption with Associated Data (AEAD).
2//!
3//! This module offers both one-shot encryption/decryption functions and a stateful API that can be
4//! used to perform streaming encryption/decryption with optional associated data (AAD). The
5//! stateful API ensures correct usage through a compile-time state machine.
6//!
7//! # Examples
8//!
9//! Using the one-shot encryption function:
10//!
11//! ```
12//! use wolf_crypto::aead::chacha20_poly1305::{encrypt, decrypt_in_place, Key};
13//!
14//! # fn main() -> Result<(), wolf_crypto::Unspecified> {
15//! let key = Key::new([0u8; 32]);
16//! let iv = [0u8; 12];
17//! let plaintext = b"Secret message";
18//! let mut ciphertext = [0u8; 14];
19//!
20//! let tag = encrypt(key.as_ref(), &iv, plaintext, &mut ciphertext, ())?;
21//! decrypt_in_place(key, iv, &mut ciphertext, (), tag)?;
22//!
23//! assert_eq!(ciphertext, *plaintext);
24//! # Ok(()) }
25//! ```
26//!
27//! Using the stateful API:
28//!
29//! ```
30//! use wolf_crypto::{aead::ChaCha20Poly1305, MakeOpaque};
31//! use wolf_crypto::mac::poly1305::Key;
32//!
33//! # fn main() -> Result<(), wolf_crypto::Unspecified> {
34//! let plaintext = b"Secret message";
35//! let aad = "Additional data";
36//! let mut ciphertext = [0u8; 14];
37//!
38//! let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [7u8; 12])
39//! .set_aad(aad).opaque()?
40//! .update(plaintext, &mut ciphertext).opaque()?
41//! .finalize();
42//!
43//! let d_tag = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [7u8; 12])
44//! .update_aad("Additional ")
45//! .opaque_bind(|aead| aead.update_aad("data"))
46//! .opaque_bind(|aead| aead.update_in_place(&mut ciphertext))
47//! .opaque_map(|aead| aead.finalize())?;
48//!
49//! assert_eq!(tag, d_tag);
50//! assert_eq!(ciphertext, *plaintext);
51//! # Ok(())}
52//! ```
53
54pub mod states;
55
56io_impls! {
57 #[doc(hidden)]
58 pub mod io;
59
60 #[doc(inline)]
61 pub use io::Aad as IoAad;
62
63 #[doc(inline)]
64 pub use io::Data as IoData;
65}
66
67use wolf_crypto_sys::{
68 ChaChaPoly_Aead,
69 wc_ChaCha20Poly1305_UpdateData, wc_ChaCha20Poly1305_UpdateAad,
70 wc_ChaCha20Poly1305_Init, wc_ChaCha20Poly1305_Final,
71 wc_ChaCha20Poly1305_Decrypt, wc_ChaCha20Poly1305_Encrypt,
72 CHACHA20_POLY1305_AEAD_DECRYPT, CHACHA20_POLY1305_AEAD_ENCRYPT,
73};
74
75#[cfg(feature = "llvm-assume")]
76use wolf_crypto_sys::{
77 CHACHA20_POLY1305_STATE_READY, CHACHA20_POLY1305_STATE_AAD, CHACHA20_POLY1305_STATE_DATA,
78 byte
79};
80
81use states::{
82 State, Init, CanUpdate, CanSetAad, CanUpdateAad,
83 Updating, UpdatingAad,
84
85 EncryptMaybeAad, DecryptMaybeAad,
86 EncryptAad, DecryptAad,
87};
88
89#[doc(inline)]
90pub use states::{Decrypt, Encrypt};
91
92use core::mem::MaybeUninit;
93use core::marker::PhantomData;
94use core::ptr::addr_of_mut;
95use crate::aead::{Aad, Tag};
96use crate::buf::{GenericIv, U12};
97use crate::mac::poly1305::GenericKey;
98use crate::opaque_res::Res;
99use crate::{can_cast_u32, const_can_cast_u32, Unspecified};
100
101#[doc(inline)]
102pub use crate::mac::poly1305::{Key, KeyRef};
103
104opaque_dbg! { ChaCha20Poly1305<Init> }
105opaque_dbg! { ChaCha20Poly1305<EncryptMaybeAad> }
106opaque_dbg! { ChaCha20Poly1305<DecryptMaybeAad> }
107opaque_dbg! { ChaCha20Poly1305<EncryptAad> }
108opaque_dbg! { ChaCha20Poly1305<DecryptAad> }
109opaque_dbg! { ChaCha20Poly1305<Encrypt> }
110opaque_dbg! { ChaCha20Poly1305<Decrypt> }
111
112#[inline(always)]
113#[must_use]
114fn oneshot_predicate<A: Aad>(plain: &[u8], out: &[u8], aad: &A) -> bool {
115 can_cast_u32(plain.len()) && out.len() >= plain.len() && aad.is_valid_size()
116}
117
118/// Encrypts data using the `ChaCha20Poly1305` AEAD.
119///
120/// # Arguments
121///
122/// * `key` - The 32-byte key material.
123/// * `iv` - The 12-byte initialization vector.
124/// * `plain` - The plaintext data to encrypt.
125/// * `out` - The buffer to store the resulting ciphertext. The buffer must be at least as large
126/// as `plain`.
127/// * `aad` - The associated data, which is authenticated but not encrypted.
128///
129/// # Returns
130///
131/// The authentication [`Tag`] for the ciphertext, used to verify the integrity and authenticity
132/// of the data during decryption.
133///
134/// # Errors
135///
136/// - The length of the plaintext is greater than [`u32::MAX`].
137/// - The length of the output buffer is less than the plaintext length.
138/// - The length of the associated data is greater than [`u32::MAX`].
139///
140/// # Example
141///
142/// ```
143/// use wolf_crypto::{aead::chacha20_poly1305::encrypt, mac::poly1305::Key};
144///
145/// let mut out = [0u8; 12];
146///
147/// let tag = encrypt(
148/// Key::new([7u8; 32]), [42u8; 12],
149/// b"hello world!", &mut out,
150/// "Some additional data"
151/// ).unwrap();
152///
153/// assert_ne!(&out, b"hello world!");
154/// # let _ = tag;
155/// ```
156pub fn encrypt<K, IV, A>(
157 key: K, iv: IV,
158 plain: &[u8], out: &mut [u8],
159 aad: A
160) -> Result<Tag, Unspecified>
161 where
162 K: GenericKey,
163 IV: GenericIv<Size = U12>,
164 A: Aad
165{
166 if !oneshot_predicate(plain, out, &aad) { return Err(Unspecified) }
167 let mut res = Res::new();
168 let mut tag = Tag::new_zeroed();
169
170 unsafe {
171 res.ensure_0(wc_ChaCha20Poly1305_Encrypt(
172 key.ptr(),
173 iv.as_slice().as_ptr(),
174 aad.ptr(),
175 aad.size(),
176 plain.as_ptr(),
177 plain.len() as u32,
178 out.as_mut_ptr(),
179 tag.as_mut_ptr()
180 ));
181 }
182
183 res.unit_err(tag)
184}
185
186/// Encrypts data in-place using the `ChaCha20Poly1305` AEAD.
187///
188/// # Arguments
189///
190/// * `key` - The 32-byte key material.
191/// * `iv` - The 12-byte initialization vector.
192/// * `in_out` - A mutable buffer containing the plaintext, which is overwritten with the ciphertext.
193/// * `aad` - The associated data, which is authenticated but not encrypted.
194///
195/// # Returns
196///
197/// The authentication [`Tag`] for the ciphertext, used to verify the integrity and authenticity
198/// of the data during decryption.
199///
200/// # Errors
201///
202/// - The length of the plaintext is greater than [`u32::MAX`].
203/// - The length of the associated data is greater than [`u32::MAX`].
204///
205/// # Example
206///
207/// ```
208/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, Key};
209///
210/// let mut in_out = *b"Hello, world!";
211/// let tag = encrypt_in_place(Key::new([7u8; 32]), [42u8; 12], &mut in_out, "additional").unwrap();
212///
213/// assert_ne!(&in_out, b"Hello, world!");
214/// # let _ = tag;
215/// ```
216pub fn encrypt_in_place<K, IV, A>(key: K, iv: IV, in_out: &mut [u8], aad: A) -> Result<Tag, Unspecified>
217 where
218 K: GenericKey,
219 IV: GenericIv<Size = U12>,
220 A: Aad
221{
222 if !(can_cast_u32(in_out.len()) && aad.is_valid_size()) { return Err(Unspecified) }
223 let mut res = Res::new();
224 let mut tag = Tag::new_zeroed();
225
226 unsafe {
227 res.ensure_0(wc_ChaCha20Poly1305_Encrypt(
228 key.ptr(),
229 iv.as_slice().as_ptr(),
230 aad.ptr(),
231 aad.size(),
232 in_out.as_ptr(),
233 in_out.len() as u32,
234 in_out.as_ptr().cast_mut(),
235 tag.as_mut_ptr()
236 ));
237 }
238
239 res.unit_err(tag)
240}
241
242/// Decrypts data using the `ChaCha20Poly1305` AEAD.
243///
244/// # Arguments
245///
246/// * `key` - The 32-byte key material.
247/// * `iv` - The 12-byte initialization vector.
248/// * `cipher` - The ciphertext to decrypt.
249/// * `out` - The buffer to store the resulting plaintext. The buffer must be at least as large as
250/// `cipher`.
251/// * `aad` - The associated data, which is authenticated but not encrypted.
252/// * `tag` - The authentication tag to verify.
253///
254/// # Errors
255///
256/// - The length of the ciphertext is greater than [`u32::MAX`].
257/// - The length of the output buffer is less than the plaintext length.
258/// - The length of the associated data is greater than [`u32::MAX`].
259/// - The verification of the authentication tag failed, indicating tampering.
260///
261/// # Example
262///
263/// ```
264/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, decrypt, Key};
265///
266/// let (key, iv, mut cipher) = (Key::new([7u8; 32]), [42u8; 12], *b"plaintext");
267/// let tag = encrypt_in_place(key.as_ref(), &iv, &mut cipher, "additional data").unwrap();
268///
269/// let mut plain = [0u8; 9];
270/// decrypt(key, iv, &cipher, &mut plain, "additional data", tag).unwrap();
271///
272/// assert_eq!(plain, *b"plaintext");
273/// ```
274pub fn decrypt<K, IV, A>(
275 key: K, iv: IV,
276 cipher: &[u8], out: &mut [u8],
277 aad: A, tag: Tag
278) -> Result<(), Unspecified>
279 where
280 K: GenericKey,
281 IV: GenericIv<Size = U12>,
282 A: Aad
283{
284 if !oneshot_predicate(cipher, out, &aad) { return Err(Unspecified) }
285 let mut res = Res::new();
286
287 unsafe {
288 res.ensure_0(wc_ChaCha20Poly1305_Decrypt(
289 key.ptr(),
290 iv.as_slice().as_ptr(),
291 aad.ptr(),
292 aad.size(),
293 cipher.as_ptr(),
294 cipher.len() as u32,
295 tag.as_ptr(),
296 out.as_mut_ptr()
297 ));
298 }
299
300 res.unit_err(())
301}
302
303/// Decrypts data in-place using the `ChaCha20Poly1305` AEAD.
304///
305/// # Arguments
306///
307/// * `key` - The 32-byte key material.
308/// * `iv` - The 12-byte initialization vector.
309/// * `in_out` - A mutable buffer containing the ciphertext, which is overwritten with the plaintext.
310/// * `aad` - The associated data, which is authenticated but not encrypted.
311/// * `tag` - The authentication tag to verify.
312///
313/// # Errors
314///
315/// - The length of the ciphertext is greater than [`u32::MAX`].
316/// - The length of the associated data is greater than [`u32::MAX`].
317/// - The verification of the authentication tag failed, indicating tampering.
318///
319/// # Example
320///
321/// ```
322/// use wolf_crypto::aead::chacha20_poly1305::{encrypt_in_place, decrypt_in_place, Key};
323///
324/// let (key, iv, mut in_out) = (Key::new([7u8; 32]), [42u8; 12], *b"plaintext");
325/// let tag = encrypt_in_place(key.as_ref(), &iv, &mut in_out, "additional data").unwrap();
326///
327/// decrypt_in_place(key, iv, &mut in_out, "additional data", tag).unwrap();
328///
329/// assert_eq!(in_out, *b"plaintext");
330/// ```
331pub fn decrypt_in_place<K, IV, A>(
332 key: K, iv: IV,
333 in_out: &mut [u8],
334 aad: A, tag: Tag
335) -> Result<(), Unspecified>
336where
337 K: GenericKey,
338 IV: GenericIv<Size = U12>,
339 A: Aad
340{
341 if !(can_cast_u32(in_out.len()) && aad.is_valid_size()) { return Err(Unspecified) }
342 let mut res = Res::new();
343
344 unsafe {
345 res.ensure_0(wc_ChaCha20Poly1305_Decrypt(
346 key.ptr(),
347 iv.as_slice().as_ptr(),
348 aad.ptr(),
349 aad.size(),
350 in_out.as_ptr(),
351 in_out.len() as u32,
352 tag.as_ptr(),
353 in_out.as_ptr().cast_mut()
354 ));
355 }
356
357 res.unit_err(())
358}
359
360/// The `ChaCha20Poly1305` ([`RFC8439`][1]) [AEAD][2].
361///
362/// `ChaCha20Poly1305` combines the [`ChaCha20`][3] stream cipher with the [`Poly1305`][4] message
363/// authentication code. `ChaCha20Poly1305` is well-regarded for efficiency and performance, with
364/// or without hardware acceleration, making it amenable to resource constrained environments.
365///
366/// # Interface
367///
368/// This crate's interface for `ChaCha20Poly1305` is designed as a compile-time state machine,
369/// ensuring errors / misuse is caught early, and without any runtime overhead.
370///
371/// The state machine for both encryption and decryption follows the following flow
372///
373/// ```txt
374/// set_aad(...)
375/// +--------------------------------------+
376/// | +---+ |
377/// | | v v finalize()
378/// +------+ +-----+ finish() +----------+ +-----+
379/// | Init | --> | AAD | ----------------> | | -----> | Tag |
380/// +------+ +-----+ | Updating | +-----+
381/// | update(...) | |
382/// +----------------------------------> | |
383/// +----------+
384/// ^ |
385/// +------+
386/// ```
387///
388/// The state machine is initialized in either decryption or encryption mode, this initial state
389/// has the following three possible transitions:
390///
391/// ```txt
392/// +------------------+
393/// +------------ | Init | --------+
394/// | +------------------+ |
395/// | | |
396/// | | update_aad(...) |
397/// | v |
398/// | +------------------+ |
399/// | | |--+ |
400/// | | AAD | | |
401/// | | |<-+ |
402/// | +------------------+ |
403/// | | |
404/// | update(...) | finish() | set_aad(...)
405/// | v |
406/// | +------------------+ |
407/// +-----------> | Updating | <-------+
408/// +------------------+
409/// |
410/// v
411/// ...
412/// ```
413///
414/// - [`update(...)`][5] path:
415/// The user encrypts or decrypts data without providing any AAD. This method is used
416/// to process the main body of the message. After processing the plaintext or ciphertext,
417/// the user can either continue updating with more data, or invoke [`finalize()`][6]
418/// to return the authentication tag.
419/// - [`set_aad`][6] path:
420/// Similar to the [`update(...)`][5] path, but this method sets the associated data (AAD),
421/// which is data that is authenticated but not encrypted. The AAD is processed first
422/// before transitioning to the `Updating` state, where data is encrypted or decrypted.
423/// AAD helps verify the integrity of the message.
424/// - [`update_aad(...)`][7] path:
425/// This method transitions to the `AAD` state, allowing the user to process associated
426/// data in chunks. It is useful in cases where the complete AAD is not available at once,
427/// and the user needs to progressively update it. Once all AAD is processed, the state
428/// transitions to `Updating` by invoking [`finish()`][8].
429///
430/// # Examples
431///
432/// ```
433/// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
434///
435/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
436/// let mut in_out = [7u8; 42];
437/// let key = Key::new([3u8; 32]);
438///
439/// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
440/// .update_in_place(&mut in_out).opaque()?
441/// .finalize();
442///
443/// assert_ne!(in_out, [7u8; 42]);
444///
445/// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
446/// .update_in_place(&mut in_out).opaque()?
447/// .finalize();
448///
449/// // PartialEq for tags is constant time
450/// assert_eq!(tag, d_tag);
451/// assert_eq!(in_out, [7u8; 42]);
452/// #
453/// # Ok(()) }
454/// ```
455///
456/// **With AAD**
457///
458/// ```
459/// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
460///
461/// # fn main() -> Result<(), wolf_crypto::Unspecified> {
462/// let mut in_out = [7u8; 42];
463/// let key = Key::new([3u8; 32]);
464///
465/// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
466/// .set_aad("hello world").opaque()?
467/// .update_in_place(&mut in_out).opaque()?
468/// .finalize();
469///
470/// assert_ne!(in_out, [7u8; 42]);
471///
472/// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
473/// .set_aad("hello world")
474/// .opaque_bind(|aead| aead.update_in_place(&mut in_out))
475/// .opaque_map(|aead| aead.finalize())?;
476///
477/// // PartialEq for tags is constant time
478/// assert_eq!(tag, d_tag);
479/// assert_eq!(in_out, [7u8; 42]);
480/// #
481/// # Ok(()) }
482/// ```
483///
484/// # Errors
485///
486/// To guarantee that the state machine is correctly used, all methods take ownership over the
487/// `ChaCha20Poly1305` instance. The `ChaCha20Poly1305` instance is always returned whether the
488/// operation failed or not, allowing for retries.
489///
490/// For example, with the [`set_aad(...)`][6] method:
491///
492/// ```txt
493/// Error!
494/// +----------+
495/// v |
496/// +--------------+ Success! +----------------+
497/// | set_aad(...) | ----------> | Updating State |
498/// +--------------+ +----------------+
499/// ```
500///
501/// While this serves its purpose in allowing retries, it can be annoying for error propagation. To
502/// remedy this, there is the [`MakeOpaque`] trait, which will convert the error type into the
503/// [`Unspecified`] type via the [`opaque`] method, as well as provide common combinatorics such as
504/// [`opaque_bind`] and [`opaque_map`].
505///
506/// [1]: https://datatracker.ietf.org/doc/html/rfc8439
507/// [2]: https://en.wikipedia.org/wiki/Authenticated_encryption
508/// [3]: crate::chacha::ChaCha20
509/// [4]: crate::mac::Poly1305
510/// [5]: ChaCha20Poly1305::update
511/// [6]: ChaCha20Poly1305::set_aad
512/// [7]: ChaCha20Poly1305::update_aad
513/// [8]: ChaCha20Poly1305::finish
514///
515/// [`MakeOpaque`]: crate::MakeOpaque
516/// [`opaque`]: crate::MakeOpaque::opaque
517/// [`opaque_bind`]: crate::MakeOpaque::opaque_bind
518/// [`opaque_map`]: crate::MakeOpaque::opaque_map
519#[must_use]
520#[repr(transparent)]
521pub struct ChaCha20Poly1305<S: State = Init> {
522 inner: ChaChaPoly_Aead,
523 _state: PhantomData<S>
524}
525
526impl ChaCha20Poly1305<Init> {
527 /// Creates a new `ChaCha20Poly1305` instance with the specified direction.
528 ///
529 /// # Arguments
530 ///
531 /// * `key` - The 32-byte key material.
532 /// * `iv` - The 12-byte initialization vector.
533 /// * `dir` - The direction of the operation (`CHACHA20_POLY1305_AEAD_ENCRYPT` or
534 /// `CHACHA20_POLY1305_AEAD_DECRYPT`).
535 ///
536 /// # Safety
537 ///
538 /// This function is unsafe as it assumes that the provided `dir` is valid.
539 fn new_with_dir<K, IV, S>(key: K, iv: IV, dir: core::ffi::c_int) -> ChaCha20Poly1305<S>
540 where
541 K: GenericKey,
542 IV: GenericIv<Size = U12>,
543 S: State
544 {
545 debug_assert!(matches!(
546 dir as core::ffi::c_uint,
547 CHACHA20_POLY1305_AEAD_ENCRYPT | CHACHA20_POLY1305_AEAD_DECRYPT
548 ));
549
550 let mut inner = MaybeUninit::<ChaChaPoly_Aead>::uninit();
551
552 unsafe {
553 let _res = wc_ChaCha20Poly1305_Init(
554 inner.as_mut_ptr(),
555 key.ptr(),
556 iv.as_slice().as_ptr(),
557 dir
558 );
559
560 debug_assert_eq!(_res, 0);
561
562 ChaCha20Poly1305::<S> {
563 inner: inner.assume_init(),
564 _state: PhantomData
565 }
566 }
567 }
568
569 /// Create a new [`ChaCha20Poly1305`] instance for either encryption or decryption.
570 ///
571 /// # Generic
572 ///
573 /// The provided `Mode` generic denotes whether this instance will be used for encryption or
574 /// decryption. The possible types are:
575 ///
576 /// * [`Decrypt`] - Initialize the instance for decryption, there is also the [`new_decrypt`][1]
577 /// convenience associated function.
578 /// * [`Encrypt`] - Initialize the instance for encryption, there is also the [`new_encrypt`][2]
579 /// convenience associated function.
580 ///
581 /// # Arguments
582 ///
583 /// * `key` - The 32 byte key material to use.
584 /// * `iv` - The 12 byte initialization vector to use.
585 ///
586 /// # Examples
587 ///
588 /// **Decryption**
589 /// ```
590 /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Decrypt}, mac::poly1305::Key};
591 ///
592 /// # let _ = {
593 /// ChaCha20Poly1305::new::<Decrypt>(Key::new([7u8; 32]), [42u8; 12])
594 /// # };
595 /// ```
596 ///
597 /// **Encryption**
598 /// ```
599 /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Encrypt}, mac::poly1305::Key};
600 ///
601 /// # let _ = {
602 /// ChaCha20Poly1305::new::<Encrypt>(Key::new([7u8; 32]), [42u8; 12])
603 /// # };
604 /// ```
605 ///
606 /// [1]: Self::new_decrypt
607 /// [2]: Self::new_encrypt
608 #[inline]
609 pub fn new<Mode: Updating>(key: impl GenericKey, iv: impl GenericIv<Size = U12>) -> ChaCha20Poly1305<Mode::InitState> {
610 Self::new_with_dir(key, iv, Mode::direction())
611 }
612
613 /// Create a new [`ChaCha20Poly1305`] instance for encryption.
614 ///
615 /// # Arguments
616 ///
617 /// * `key` - The 32 byte key material to use.
618 /// * `iv` - The 12 byte initialization vector to use.
619 ///
620 /// # Example
621 ///
622 /// ```
623 /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};
624 ///
625 /// # let _ = {
626 /// ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
627 /// # };
628 /// ```
629 ///
630 /// # Note
631 ///
632 /// This is a convenience associated function for calling [`ChaCha20Poly1305::new::<Encrypt>(...)`][1],
633 /// circumventing the need for importing the [`Encrypt`] marker type.
634 ///
635 /// [1]: Self::new
636 #[inline]
637 pub fn new_encrypt<K, IV>(key: K, iv: IV) -> ChaCha20Poly1305<<Encrypt as Updating>::InitState>
638 where
639 K: GenericKey,
640 IV: GenericIv<Size = U12>
641 {
642 Self::new::<Encrypt>(key, iv)
643 }
644
645 /// Create a new [`ChaCha20Poly1305`] instance for decryption.
646 ///
647 /// # Arguments
648 ///
649 /// * `key` - The 32 byte key material to use.
650 /// * `iv` - The 12 byte initialization vector to use.
651 ///
652 /// # Example
653 ///
654 /// ```
655 /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};
656 ///
657 /// # let _ = {
658 /// ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
659 /// # };
660 /// ```
661 ///
662 /// # Note
663 ///
664 /// This is a convenience associated function for calling [`ChaCha20Poly1305::new::<Decrypt>(...)`][1],
665 /// circumventing the need for importing the [`Decrypt`] marker type.
666 ///
667 /// [1]: Self::new
668 #[inline]
669 pub fn new_decrypt<K, IV>(key: K, iv: IV) -> ChaCha20Poly1305<<Decrypt as Updating>::InitState>
670 where
671 K: GenericKey,
672 IV: GenericIv<Size = U12>
673 {
674 Self::new::<Decrypt>(key, iv)
675 }
676}
677
678impl<S: State> ChaCha20Poly1305<S> {
679 /// Transitions the state of the `ChaCha20Poly1305` instance to a new state.
680 ///
681 /// # Type Parameters
682 ///
683 /// * `N` - The new state type.
684 ///
685 /// # Returns
686 ///
687 /// A new `ChaCha20Poly1305` instance with the updated state.
688 #[inline]
689 pub(crate) const fn with_state<N: State>(self) -> ChaCha20Poly1305<N> {
690 // SAFETY: we're just updating the phantom data state, same everything
691 unsafe { core::mem::transmute(self) }
692 }
693}
694
695impl<S: CanUpdateAad> ChaCha20Poly1305<S> {
696 /// Updates the AAD (Additional Authenticated Data) without performing any safety checks in
697 /// release builds.
698 ///
699 /// # Safety
700 ///
701 /// The caller must ensure that the AAD length is safely representable as a `u32`.
702 ///
703 /// # Arguments
704 ///
705 /// * `aad` - The additional authenticated data to include in the authentication tag.
706 ///
707 /// # Panics
708 ///
709 /// Panics in debug mode if the AAD size is invalid or if the internal state is incorrect.
710 #[cfg_attr(debug_assertions, track_caller)]
711 #[inline]
712 unsafe fn update_aad_unchecked<A: Aad>(&mut self, aad: A) {
713 debug_assert!(aad.is_valid_size());
714
715 #[cfg(feature = "llvm-assume")] {
716 // Guaranteed via trait based state machine
717 core::hint::assert_unchecked(
718 self.inner.state == CHACHA20_POLY1305_STATE_READY as byte ||
719 self.inner.state == CHACHA20_POLY1305_STATE_AAD as byte
720 );
721
722 core::hint::assert_unchecked(
723 self.inner.state != CHACHA20_POLY1305_STATE_DATA as byte
724 );
725 }
726
727 let _res = wc_ChaCha20Poly1305_UpdateAad(
728 addr_of_mut!(self.inner),
729 aad.ptr(),
730 aad.size()
731 );
732
733 debug_assert_eq!(_res, 0);
734 }
735
736 io_impls! {
737 /// Returns an `Aad<S::Updating, IO>` struct which implements the `Read` and `Write` traits
738 /// for processing Additional Authenticated Data (AAD).
739 ///
740 /// This method allows for streaming AAD processing, which is useful when the entire AAD
741 /// is not available at once or when working with I/O streams.
742 ///
743 /// # Arguments
744 ///
745 /// * `io`: An implementor of the `Read` or `Write` traits. The data passed to and from
746 /// this `io` implementor will be authenticated as AAD.
747 ///
748 /// # Returns
749 ///
750 /// An `Aad<S::Updating, IO>` struct that wraps the ChaCha20Poly1305 instance and the
751 /// provided IO type.
752 ///
753 /// # Example
754 ///
755 /// ```
756 /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
757 /// use wolf_crypto::MakeOpaque;
758 #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "use embedded_io::Write;")]
759 #[cfg_attr(feature = "std", doc = "use std::io::Write;")]
760 ///
761 #[cfg_attr(
762 all(feature = "embedded-io", not(feature = "std")),
763 doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
764 )]
765 #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
766 /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
767 /// let mut some_io_write_implementor = [7u8; 64];
768 ///
769 /// let mut io = ChaCha20Poly1305::new_encrypt(key, iv)
770 /// .aad_io(some_io_write_implementor.as_mut_slice());
771 ///
772 /// let read = io.write(b"hello world")?;
773 /// let (aead, _my_writer) = io.finish();
774 ///
775 /// assert_eq!(&some_io_write_implementor[..read], b"hello world");
776 ///
777 /// let tag = aead.finalize();
778 /// # assert_ne!(tag, wolf_crypto::aead::Tag::new_zeroed()); // no warnings
779 /// # Ok(()) }
780 /// ```
781 #[inline]
782 pub const fn aad_io<IO>(self, io: IO) -> IoAad<S::Updating, IO> {
783 io::Aad::new(self.with_state(), io)
784 }
785 }
786
787 /// Update the underlying message authentication code without encrypting the data.
788 ///
789 /// This transitions to the streaming state for updating the AAD, allowing for partial updates.
790 /// If you already have the entire AAD, consider using [`set_aad`] instead.
791 ///
792 /// # Arguments
793 ///
794 /// * `aad` - The additional authenticated data to include in the authentication [`Tag`].
795 ///
796 /// # Errors
797 ///
798 /// If the length of the AAD is greater than [`u32::MAX`].
799 ///
800 /// # Example
801 ///
802 /// ```
803 /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};
804 ///
805 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
806 /// let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
807 /// .update_aad("hello world").opaque()?
808 /// .update_aad("!").opaque()?
809 /// .finish()
810 /// .finalize();
811 ///
812 /// let d_tag = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
813 /// .update_aad("hello world!").opaque()? // equivalent to processing in parts
814 /// .finish()
815 /// .finalize();
816 ///
817 /// assert_eq!(tag, d_tag);
818 /// # Ok(()) }
819 /// ```
820 ///
821 /// [`set_aad`]: ChaCha20Poly1305::set_aad
822 #[inline]
823 pub fn update_aad<A: Aad>(mut self, aad: A) -> Result<ChaCha20Poly1305<S::Updating>, Self> {
824 if !aad.is_valid_size() { return Err(self) }
825 unsafe { self.update_aad_unchecked(aad); }
826 Ok(self.with_state())
827 }
828}
829
830impl<S: CanUpdate> ChaCha20Poly1305<S> {
831 /// Performs an unchecked in-place update of the `data` buffer.
832 ///
833 /// # Safety
834 ///
835 /// The caller must ensure that the length of `data` can be safely cast to `u32`.
836 #[inline]
837 unsafe fn update_in_place_unchecked(&mut self, data: &mut [u8]) {
838 debug_assert!(can_cast_u32(data.len()));
839
840 #[cfg(feature = "llvm-assume")]
841 // Guaranteed via trait based state machine
842 core::hint::assert_unchecked(!( // written like this to be an exact negation of
843 // the failure condition
844 self.inner.state != CHACHA20_POLY1305_STATE_READY as byte
845 && self.inner.state != CHACHA20_POLY1305_STATE_AAD as byte
846 && self.inner.state != CHACHA20_POLY1305_STATE_DATA as byte
847 ));
848
849 // INFALLIBLE
850 //
851 // https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/chacha20_poly1305.c#L247
852 //
853 // The functions preconditions are as follows:
854 //
855 // - aead != NULL /\ inData != NULL /\ outData != NULL
856 // - state == CHACHA20_POLY1305_STATE_READY
857 // /\ state == CHACHA20_POLY1305_STATE_AAD
858 // /\ state == CHACHA20_POLY1305_STATE_DATA
859 //
860 // Which we satisfy via the type system.
861 //
862 // The internal function calls we have also already shown to be infallible. These being:
863 //
864 // - wc_Poly1305_Pad (see this crates poly1305 implementations infallibility commentary)
865 // - wc_Poly1305_Update (see this crates poly1305 implementations infallibility commentary)
866 // - wc_ChaCha_Process (see this crates chacha implementation's process_unchecked commentary)
867 //
868 // Which means both update_in_place_unchecked and update_unchecked are infallible.
869
870 let _res = wc_ChaCha20Poly1305_UpdateData(
871 addr_of_mut!(self.inner),
872 // See comment at:
873 // https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/chacha20_poly1305.c#L246
874 // if you were wondering if it is safe to have the in and out ptr be the same.
875 data.as_ptr(),
876 data.as_ptr().cast_mut(),
877 data.len() as u32
878 );
879
880 debug_assert_eq!(_res, 0);
881 }
882
883 /// Performs an unchecked update of the `data`, writing the `output` to a separate buffer.
884 ///
885 /// # Safety
886 ///
887 /// The caller must ensure that:
888 /// - `data.len() <= output.len()`
889 /// - The length of `data` can be safely cast to `u32`.
890 #[inline]
891 unsafe fn update_unchecked(&mut self, data: &[u8], output: &mut [u8]) {
892 debug_assert!(data.len() <= output.len());
893 debug_assert!(can_cast_u32(data.len()));
894
895 #[cfg(feature = "llvm-assume")] {
896 // Guaranteed via trait based state machine
897 core::hint::assert_unchecked(
898 self.inner.state == CHACHA20_POLY1305_STATE_READY as byte
899 || self.inner.state == CHACHA20_POLY1305_STATE_AAD as byte
900 || self.inner.state == CHACHA20_POLY1305_STATE_DATA as byte
901 );
902 }
903
904 // See the update_in_place_unchecked commentary regarding the infallibility of this.
905
906 let _res = wc_ChaCha20Poly1305_UpdateData(
907 addr_of_mut!(self.inner),
908 data.as_ptr(),
909 output.as_mut_ptr(),
910 data.len() as u32
911 );
912
913 debug_assert_eq!(_res, 0);
914 }
915
916 /// Predicate to check if the update operation can proceed.
917 ///
918 /// Ensures that the `input` length can be cast to `u32` and that the `output` buffer is large
919 /// enough.
920 #[inline]
921 #[must_use]
922 const fn update_predicate(input: &[u8], output: &[u8]) -> bool {
923 can_cast_u32(input.len()) && output.len() >= input.len()
924 }
925
926 /// Encrypt / Decrypt the provided `in_out` data in-place.
927 ///
928 /// # Arguments
929 ///
930 /// * `in_out` - A mutable slice of data to be encrypted / decrypted in place.
931 ///
932 /// # Errors
933 ///
934 /// If the length of `in_out` is greater than `u32::MAX`.
935 ///
936 /// # Example
937 ///
938 /// ```
939 /// use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
940 ///
941 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
942 /// let mut in_out = [7u8; 42];
943 /// let key = Key::new([3u8; 32]);
944 ///
945 /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
946 /// .set_aad("hello world").opaque()?
947 /// .update_in_place(&mut in_out).opaque()?
948 /// .finalize();
949 ///
950 /// assert_ne!(in_out, [7u8; 42]);
951 ///
952 /// let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
953 /// .set_aad("hello world")
954 /// .opaque_bind(|aead| aead.update_in_place(&mut in_out))
955 /// .opaque_map(|aead| aead.finalize())?;
956 ///
957 /// assert_eq!(tag, d_tag);
958 /// assert_eq!(in_out, [7u8; 42]);
959 /// # Ok(()) }
960 /// ```
961 #[inline]
962 pub fn update_in_place(mut self, in_out: &mut [u8]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
963 if can_cast_u32(in_out.len()) {
964 unsafe { self.update_in_place_unchecked(in_out) };
965 Ok(self.with_state())
966 } else {
967 Err(self)
968 }
969 }
970
971 /// Encrypt / Decrypt the provided `in_out` data in-place.
972 ///
973 /// This method is similar to [`update_in_place`], but accepts a fixed-size array, allowing for
974 /// potential optimizations and compile-time checks.
975 ///
976 /// # Arguments
977 ///
978 /// * `in_out` - A mutable fixed-size array of data to be encrypted or decrypted in place.
979 ///
980 /// # Errors
981 ///
982 /// If the length of `in_out` is greater than `u32::MAX`.
983 ///
984 /// # Example
985 ///
986 /// ```
987 /// use wolf_crypto::aead::{ChaCha20Poly1305};
988 /// use wolf_crypto::mac::poly1305::Key;
989 /// use wolf_crypto::MakeOpaque;
990 ///
991 /// let mut data = [42u8; 64];
992 /// let key = Key::new([0u8; 32]);
993 /// let iv = [0u8; 12];
994 ///
995 /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
996 /// .update_in_place_sized(&mut data).unwrap()
997 /// .finalize();
998 ///
999 /// assert_ne!(data, [42u8; 64]);
1000 ///
1001 /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1002 /// .update_in_place_sized(&mut data).unwrap()
1003 /// .finalize();
1004 ///
1005 /// assert_eq!(data, [42u8; 64]);
1006 /// assert_eq!(tag, d_tag);
1007 /// ```
1008 ///
1009 /// [`update_in_place`]: Self::update_in_place
1010 #[inline]
1011 pub fn update_in_place_sized<const C: usize>(mut self, in_out: &mut [u8; C]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
1012 if const_can_cast_u32::<C>() {
1013 unsafe { self.update_in_place_unchecked(in_out) };
1014 Ok(self.with_state())
1015 } else {
1016 Err(self)
1017 }
1018 }
1019
1020 /// Encrypt / Decrypt the provided `data` into the `output` buffer.
1021 ///
1022 /// # Arguments
1023 ///
1024 /// * `data` - A slice of data to be encrypted or decrypted.
1025 /// * `output` - A mutable slice where the result will be written. It must be at least as large
1026 /// as `data`.
1027 ///
1028 /// # Errors
1029 ///
1030 /// - The length of `data` is greater than `u32::MAX`.
1031 /// - The `output` buffer is smaller than the `data` buffer.
1032 ///
1033 /// # Example
1034 ///
1035 /// ```
1036 /// use wolf_crypto::aead::{ChaCha20Poly1305};
1037 /// use wolf_crypto::mac::poly1305::Key;
1038 /// use wolf_crypto::MakeOpaque;
1039 ///
1040 /// let data = [42u8; 64];
1041 /// let mut out = [0u8; 64];
1042 /// let key = Key::new([0u8; 32]);
1043 /// let iv = [0u8; 12];
1044 ///
1045 /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1046 /// .update(&data, &mut out).unwrap()
1047 /// .finalize();
1048 ///
1049 /// assert_ne!(out, data);
1050 ///
1051 /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1052 /// .update_in_place(&mut out).unwrap()
1053 /// .finalize();
1054 ///
1055 /// assert_eq!(out, data);
1056 /// assert_eq!(tag, d_tag);
1057 /// ```
1058 pub fn update(mut self, data: &[u8], output: &mut [u8]) -> Result<ChaCha20Poly1305<S::Mode>, Self> {
1059 if Self::update_predicate(data, output) {
1060 unsafe { self.update_unchecked(data, output) };
1061 Ok(self.with_state())
1062 } else {
1063 Err(self)
1064 }
1065 }
1066
1067 io_impls! {
1068 /// Returns a `Data<S::Mode, IO>` struct which implements the `Read` trait for
1069 /// encrypting / decrypting data.
1070 ///
1071 /// This method allows for streaming data processing, which is useful when working
1072 /// with large amounts of data or I/O streams.
1073 ///
1074 /// # Arguments
1075 ///
1076 /// * `io`: An implementor of the `Read` trait. The data read from this `io` implementor
1077 /// will be encrypted or decrypted depending on the mode of the ChaCha20Poly1305 instance.
1078 ///
1079 /// # Returns
1080 ///
1081 /// A `Data<S::Mode, IO>` struct that wraps the ChaCha20Poly1305 instance and the
1082 /// provided IO type.
1083 ///
1084 /// # Example
1085 ///
1086 /// ```
1087 /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1088 /// use wolf_crypto::MakeOpaque;
1089 #[cfg_attr(all(feature = "embedded-io", not(feature = "std")), doc = "use embedded_io::Read;")]
1090 #[cfg_attr(feature = "std", doc = "use std::io::Read;")]
1091 ///
1092 #[cfg_attr(
1093 all(feature = "embedded-io", not(feature = "std")),
1094 doc = "# fn main() -> Result<(), wolf_crypto::Unspecified> {"
1095 )]
1096 #[cfg_attr(feature = "std", doc = "# fn main() -> Result<(), Box<dyn std::error::Error>> {")]
1097 /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
1098 /// let plaintext = b"hello world";
1099 ///
1100 /// // Encrypt
1101 /// let mut encrypted = [0u8; 32];
1102 /// let mut encrypt_io = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1103 /// .data_io(&plaintext[..]);
1104 /// let encrypted_len = encrypt_io.read(&mut encrypted)?;
1105 /// let (aead, _) = encrypt_io.finish();
1106 /// let tag = aead.finalize();
1107 ///
1108 /// // Decrypt
1109 /// let mut decrypted = [0u8; 32];
1110 /// let mut decrypt_io = ChaCha20Poly1305::new_decrypt(key, iv)
1111 /// .data_io(&encrypted[..encrypted_len]);
1112 /// let decrypted_len = decrypt_io.read(&mut decrypted)?;
1113 /// let (aead, _) = decrypt_io.finish();
1114 /// let decrypted_tag = aead.finalize();
1115 ///
1116 /// assert_eq!(&decrypted[..decrypted_len], plaintext);
1117 /// assert_eq!(tag, decrypted_tag);
1118 /// # Ok(()) }
1119 /// ```
1120 pub const fn data_io<IO>(self, io: IO) -> IoData<S::Mode, IO> {
1121 io::Data::new(self.with_state(), io)
1122 }
1123 }
1124}
1125
1126impl<S: CanSetAad> ChaCha20Poly1305<S> {
1127 /// Sets the Additional Authenticated Data (AAD) for the AEAD operation.
1128 ///
1129 /// # Arguments
1130 ///
1131 /// * `aad` - The additional authenticated data to include in the authentication tag.
1132 ///
1133 /// # Example
1134 ///
1135 /// ```
1136 /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1137 ///
1138 /// let key = Key::new([7u8; 32]);
1139 /// let iv = [42u8; 12];
1140 ///
1141 /// let aead = ChaCha20Poly1305::new_encrypt(key, iv)
1142 /// .set_aad("additional data").unwrap();
1143 /// # drop(aead);
1144 /// ```
1145 ///
1146 /// # Errors
1147 ///
1148 /// If the length of the AAD is greater than `u32::MAX`.
1149 ///
1150 /// # Notes
1151 ///
1152 /// - The AAD contributes to the authentication tag but is not part of the encrypted output.
1153 /// - If you need to provide the AAD in multiple parts, consider using [`update_aad`] instead.
1154 ///
1155 /// [`update_aad`]: ChaCha20Poly1305::update_aad
1156 #[inline]
1157 pub fn set_aad<A: Aad>(
1158 mut self,
1159 aad: A
1160 ) -> Result<ChaCha20Poly1305<<S as CanSetAad>::Mode>, Self>
1161 {
1162 if aad.is_valid_size() {
1163 unsafe { self.update_aad_unchecked(aad); }
1164 Ok(self.with_state())
1165 } else {
1166 Err(self)
1167 }
1168 }
1169}
1170
1171impl<S: UpdatingAad> ChaCha20Poly1305<S> {
1172 /// Signals that no more Additional Authenticated Data (AAD) will be provided, transitioning the
1173 /// cipher to the data processing state.
1174 ///
1175 /// This method finalizes the AAD input phase. After calling `finish`, you may [`finalize`] the
1176 /// state machine, or begin updating the cipher with data to be encrypted / decrypted.
1177 ///
1178 /// # Example
1179 ///
1180 /// ```
1181 /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1182 /// use wolf_crypto::MakeOpaque;
1183 ///
1184 /// let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
1185 ///
1186 /// let tag = ChaCha20Poly1305::new_encrypt(key, iv)
1187 /// .update_aad("additional ")
1188 /// .opaque_bind(|aead| aead.update_aad("data"))
1189 /// .opaque_bind(|aead| aead.update_aad("..."))
1190 /// .opaque_map(|aead| aead.finish())
1191 /// // (just use Poly1305 directly if you're doing this)
1192 /// .opaque_map(|aead| aead.finalize()).unwrap();
1193 /// # assert_ne!(tag, wolf_crypto::aead::Tag::new_zeroed()); // no warnings
1194 /// ```
1195 ///
1196 /// [`finalize`]: ChaCha20Poly1305::finalize
1197 pub const fn finish(self) -> ChaCha20Poly1305<S::Mode> {
1198 self.with_state()
1199 }
1200
1201 /// Update the underlying message authentication code without encrypting the data or taking
1202 /// ownership of the [`ChaCha20Poly1305`] instance.
1203 ///
1204 /// This method is only available in the streaming state, making partial updates less of a
1205 /// hassle.
1206 ///
1207 /// # Arguments
1208 ///
1209 /// * `aad` - The additional authenticated data to include in the authentication [`Tag`].
1210 ///
1211 /// # Errors
1212 ///
1213 /// If the length of the AAD is greater than [`u32::MAX`].
1214 ///
1215 /// # Example
1216 ///
1217 /// ```
1218 /// use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};
1219 ///
1220 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1221 /// let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
1222 /// .set_aad("hello world! Beautiful weather.")
1223 /// .opaque_map(|aead| aead.finalize())?;
1224 ///
1225 /// let mut d_cipher = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
1226 /// .update_aad("hello world").opaque()?;
1227 ///
1228 /// // does not take ownership
1229 /// d_cipher.update_aad_streaming("! ")?;
1230 /// d_cipher.update_aad_streaming("Beautiful weather.")?;
1231 ///
1232 /// let d_tag = d_cipher.finish().finalize();
1233 ///
1234 /// assert_eq!(tag, d_tag);
1235 /// # Ok(()) }
1236 /// ```
1237 pub fn update_aad_streaming<A: Aad>(&mut self, aad: A) -> Result<(), Unspecified> {
1238 if aad.is_valid_size() {
1239 unsafe { self.update_aad_unchecked(aad); }
1240 Ok(())
1241 } else {
1242 Err(Unspecified)
1243 }
1244 }
1245}
1246
1247impl<S: Updating> ChaCha20Poly1305<S> {
1248 /// Finalizes the AEAD operation computing and returning the authentication [`Tag`].
1249 ///
1250 /// # Returns
1251 ///
1252 /// The authentication [`Tag`], resulting from the processed AAD and encryption / decryption
1253 /// operations.
1254 ///
1255 /// # Security
1256 ///
1257 /// On decryption, the returned [`Tag`] should be ensured to be equivalent to the [`Tag`]
1258 /// associated with the ciphertext. The decrypted ciphertext **should not be trusted** if
1259 /// the tags do not match.
1260 ///
1261 /// Also, the comparison should not be done outside the [`Tag`] type, you **must not** call
1262 /// `as_slice()` or anything for the comparison. **ALWAYS** leverage the [`Tag`]'s `PartialEq`
1263 /// implementation.
1264 ///
1265 /// # Example
1266 ///
1267 /// ```
1268 /// use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
1269 ///
1270 /// let key = Key::new([7u8; 32]);
1271 /// let iv = [42u8; 12];
1272 /// let mut data = [0u8; 64];
1273 ///
1274 /// let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1275 /// .set_aad("additional data").unwrap()
1276 /// .update_in_place(&mut data).unwrap()
1277 /// .finalize();
1278 ///
1279 /// // be sure to keep the tag around! important!
1280 ///
1281 /// // On decryption, we **must** ensure that the resulting tag matches
1282 /// // the provided tag.
1283 ///
1284 /// let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
1285 /// .set_aad("additional data").unwrap()
1286 /// .update_in_place(&mut data).unwrap()
1287 /// .finalize();
1288 ///
1289 /// assert_eq!(data, [0u8; 64]);
1290 ///
1291 /// // most importantly!
1292 /// assert_eq!(tag, d_tag);
1293 /// ```
1294 #[inline]
1295 pub fn finalize(mut self) -> Tag {
1296 let mut tag = Tag::new_zeroed();
1297
1298 // INFALLIBLE
1299 //
1300 // The only way this function can fail is via the preconditions or an internal function
1301 // failing. All internal functions are infallible, as described in this crate's poly1305
1302 // commentary.
1303 //
1304 // The preconditions are as follows:
1305 //
1306 // - state == CHACHA20_POLY1305_STATE_AAD \/ state == CHACHA20_POLY1305_STATE_DATA
1307 // - aead != null /\ outAuthTag != null
1308 //
1309 // The inherited preconditions from the internal function calls are respected in the same
1310 // way that we respect them in the Poly1305 module, using the same types, et cetera.
1311
1312 unsafe {
1313 let _res = wc_ChaCha20Poly1305_Final(
1314 addr_of_mut!(self.inner),
1315 tag.as_mut_ptr()
1316 );
1317
1318 debug_assert_eq!(_res, 0);
1319 }
1320
1321 tag
1322 }
1323
1324 /// Encrypt / Decrypt the provided `in_out` data in-place without taking ownership of the AEAD
1325 /// instance.
1326 ///
1327 /// # Arguments
1328 ///
1329 /// * `in_out` - A mutable slice of data to be encrypted / decrypted in place.
1330 ///
1331 /// # Returns
1332 ///
1333 /// A reference to the updated `in_out` slice on success.
1334 ///
1335 /// # Errors
1336 ///
1337 /// Returns `Unspecified` if the length of `in_out` is greater than `u32::MAX`.
1338 ///
1339 /// # Example
1340 ///
1341 /// ```
1342 /// # use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};
1343 /// #
1344 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1345 /// # let mut in_out1 = [7u8; 42];
1346 /// # let mut in_out2 = [8u8; 42];
1347 /// # let key = Key::new([3u8; 32]);
1348 /// #
1349 /// let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
1350 /// .set_aad("hello world").opaque()?;
1351 ///
1352 /// aead.update_in_place_streaming(&mut in_out1)?;
1353 /// aead.update_in_place_streaming(&mut in_out2)?;
1354 ///
1355 /// let tag = aead.finalize();
1356 ///
1357 /// assert_ne!(in_out1, [7u8; 42]);
1358 /// assert_ne!(in_out2, [8u8; 42]);
1359 /// # Ok(()) }
1360 /// ```
1361 pub fn update_in_place_streaming<'io>(&mut self, in_out: &'io mut [u8]) -> Result<&'io mut [u8], Unspecified> {
1362 if can_cast_u32(in_out.len()) {
1363 unsafe { self.update_in_place_unchecked(in_out) };
1364 Ok(in_out)
1365 } else {
1366 Err(Unspecified)
1367 }
1368 }
1369
1370 /// Encrypt / Decrypt the provided `input` data into the `output` buffer without taking
1371 /// ownership of the AEAD instance.
1372 ///
1373 /// # Arguments
1374 ///
1375 /// * `input` - A slice of data to be encrypted / decrypted.
1376 /// * `output` - A mutable slice where the result will be written. It must be at least as large
1377 /// as `input`.
1378 ///
1379 /// # Errors
1380 ///
1381 /// - The length of `input` is greater than `u32::MAX`.
1382 /// - The `output` buffer is smaller than the `input` buffer.
1383 ///
1384 /// # Example
1385 ///
1386 /// ```
1387 /// # use wolf_crypto::aead::{ChaCha20Poly1305};
1388 /// # use wolf_crypto::mac::poly1305::Key;
1389 /// # use wolf_crypto::MakeOpaque;
1390 /// #
1391 /// # fn main() -> Result<(), wolf_crypto::Unspecified> {
1392 /// # let data1 = [42u8; 32];
1393 /// # let data2 = [43u8; 32];
1394 /// # let mut out1 = [0u8; 32];
1395 /// # let mut out2 = [0u8; 32];
1396 /// # let key = Key::new([0u8; 32]);
1397 /// # let iv = [0u8; 12];
1398 /// #
1399 /// let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
1400 /// .set_aad("additional data").opaque()?;
1401 ///
1402 /// aead.update_streaming(&data1, &mut out1)?;
1403 /// aead.update_streaming(&data2, &mut out2)?;
1404 ///
1405 /// let tag = aead.finalize();
1406 ///
1407 /// assert_ne!(out1, data1);
1408 /// assert_ne!(out2, data2);
1409 /// # Ok(()) }
1410 /// ```
1411 pub fn update_streaming(&mut self, input: &[u8], output: &mut [u8]) -> Result<(), Unspecified> {
1412 if Self::update_predicate(input, output) {
1413 unsafe { self.update_unchecked(input, output) };
1414 Ok(())
1415 } else {
1416 Err(Unspecified)
1417 }
1418 }
1419}
1420
1421#[cfg(test)]
1422mod tests {
1423 use crate::mac::poly1305::Key;
1424 use core::{
1425 slice,
1426 };
1427 use super::*;
1428
1429 #[test]
1430 fn type_state_machine() {
1431 let key = Key::new([0u8; 32]);
1432
1433 let mut cipher = [69, 69, 69, 69];
1434
1435 let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), [0u8; 12])
1436 .set_aad(Some(Some(Some(())))).unwrap()
1437 .update_in_place(cipher.as_mut_slice()).unwrap()
1438 .finalize();
1439
1440 let new_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), [0u8; 12])
1441 .set_aad(()).unwrap()
1442 .update_in_place(cipher.as_mut_slice()).unwrap()
1443 .finalize();
1444
1445 assert_eq!(tag, new_tag);
1446 assert_eq!(cipher, [69, 69, 69, 69]);
1447 }
1448
1449 macro_rules! bogus_slice {
1450 ($size:expr) => {{
1451 let src = b"hello world";
1452 unsafe { slice::from_raw_parts(src.as_ptr(), $size) }
1453 }};
1454 }
1455
1456 #[test]
1457 fn oneshot_size_predicate_fail() {
1458 // I am not allocating the maximum number for u32
1459 let slice = bogus_slice!(u32::MAX as usize + 1);
1460 let out = slice;
1461 assert!(!oneshot_predicate(slice, out, &()))
1462 }
1463
1464 #[test]
1465 fn oneshot_size_predicate() {
1466 let slice = bogus_slice!(u32::MAX as usize - 1);
1467 let out = slice;
1468 assert!(oneshot_predicate(slice, out, &()))
1469 }
1470
1471 #[test]
1472 fn oneshot_size_predicate_too_small_out() {
1473 let slice = bogus_slice!(u32::MAX as usize - 1);
1474 let out = bogus_slice!(u32::MAX as usize - 2);
1475 assert!(!oneshot_predicate(slice, out, &()));
1476 }
1477}
1478
1479#[cfg(test)]
1480mod property_tests {
1481 use super::*;
1482 use crate::aes::test_utils::{BoundList};
1483 use crate::buf::Nonce;
1484 use crate::mac::poly1305::Key;
1485 use proptest::{prelude::*, proptest};
1486
1487 proptest! {
1488 // these take some time. I ran with 50k cases once, but I cannot wait for these to pass
1489 // each time I run the tests.
1490 #![proptest_config(ProptestConfig::with_cases(5_000))]
1491
1492 #[test]
1493 fn bijectivity(
1494 input in any::<BoundList<1024>>(),
1495 key in any::<Key>(),
1496 iv in any::<Nonce>()
1497 ) {
1498 let mut output = input.create_self();
1499 let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), iv.copy())
1500 .update(input.as_slice(), output.as_mut_slice()).unwrap()
1501 .finalize();
1502
1503 if output.len() >= 6 {
1504 prop_assert_ne!(output.as_slice(), input.as_slice());
1505 }
1506
1507 let mut decrypted = output.create_self();
1508 let d_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), iv)
1509 .update(output.as_slice(), decrypted.as_mut_slice()).unwrap()
1510 .finalize();
1511
1512 prop_assert_eq!(tag, d_tag);
1513 prop_assert_eq!(decrypted.as_slice(), input.as_slice());
1514 }
1515
1516 #[test]
1517 fn bijectivity_with_aad(
1518 input in any::<BoundList<1024>>(),
1519 key in any::<Key>(),
1520 iv in any::<Nonce>(),
1521 aad in any::<Option<String>>()
1522 ) {
1523 let mut output = input.create_self();
1524 let tag = ChaCha20Poly1305::new::<Encrypt>(key.as_ref(), iv.copy())
1525 .set_aad(aad.as_ref()).unwrap()
1526 .update(input.as_slice(), output.as_mut_slice()).unwrap()
1527 .finalize();
1528
1529 if output.len() >= 6 {
1530 prop_assert_ne!(output.as_slice(), input.as_slice());
1531 }
1532
1533 let mut decrypted = output.create_self();
1534 let d_tag = ChaCha20Poly1305::new::<Decrypt>(key.as_ref(), iv)
1535 .set_aad(aad.as_ref()).unwrap()
1536 .update(output.as_slice(), decrypted.as_mut_slice()).unwrap()
1537 .finalize();
1538
1539 prop_assert_eq!(tag, d_tag);
1540 prop_assert_eq!(decrypted.as_slice(), input.as_slice());
1541 }
1542
1543 #[test]
1544 fn oneshot_bijectivity(
1545 input in any::<BoundList<1024>>(),
1546 key in any::<Key>(),
1547 iv in any::<Nonce>()
1548 ) {
1549 let mut output = input.create_self();
1550
1551 let tag = encrypt(
1552 key.as_ref(), iv.copy(),
1553 input.as_slice(), output.as_mut_slice(),
1554 ()
1555 ).unwrap();
1556
1557 if output.len() >= 6 {
1558 prop_assert_ne!(output.as_slice(), input.as_slice());
1559 }
1560
1561 let mut decrypted = output.create_self();
1562 prop_assert!(decrypt(
1563 key.as_ref(), iv,
1564 output.as_slice(), decrypted.as_mut_slice(),
1565 (), tag
1566 ).is_ok());
1567
1568 prop_assert_eq!(input.as_slice(), decrypted.as_slice());
1569 }
1570
1571 #[test]
1572 fn oneshot_bijectivity_with_aad(
1573 input in any::<BoundList<1024>>(),
1574 key in any::<Key>(),
1575 iv in any::<Nonce>(),
1576 aad in any::<Option<String>>()
1577 ) {
1578 let mut output = input.create_self();
1579
1580 let tag = encrypt(
1581 key.as_ref(), iv.copy(),
1582 input.as_slice(), output.as_mut_slice(),
1583 aad.as_ref()
1584 ).unwrap();
1585
1586 if output.len() >= 6 {
1587 prop_assert_ne!(output.as_slice(), input.as_slice());
1588 }
1589
1590 let mut decrypted = output.create_self();
1591 prop_assert!(decrypt(
1592 key.as_ref(), iv,
1593 output.as_slice(), decrypted.as_mut_slice(),
1594 aad.as_ref(), tag
1595 ).is_ok());
1596
1597 prop_assert_eq!(input.as_slice(), decrypted.as_slice());
1598 }
1599 }
1600}