ChaCha20Poly1305

Struct ChaCha20Poly1305 

Source
pub struct ChaCha20Poly1305<S: State = Init> { /* private fields */ }
Available on crate feature allow-non-fips only.
Expand description

The ChaCha20Poly1305 (RFC8439) AEAD.

ChaCha20Poly1305 combines the ChaCha20 stream cipher with the Poly1305 message authentication code. ChaCha20Poly1305 is well-regarded for efficiency and performance, with or without hardware acceleration, making it amenable to resource constrained environments.

§Interface

This crate’s interface for ChaCha20Poly1305 is designed as a compile-time state machine, ensuring errors / misuse is caught early, and without any runtime overhead.

The state machine for both encryption and decryption follows the following flow

                      set_aad(...)
  +--------------------------------------+
  |           +---+                      |
  |           |   v                      v           finalize()
+------+     +-----+   finish()        +----------+        +-----+
| Init | --> | AAD | ----------------> |          | -----> | Tag |
+------+     +-----+                   | Updating |        +-----+
  |                   update(...)      |          |
  +----------------------------------> |          |
                                       +----------+
                                         ^      |
                                         +------+

The state machine is initialized in either decryption or encryption mode, this initial state has the following three possible transitions:

                +------------------+
  +------------ |       Init       | --------+
  |             +------------------+         |
  |               |                          |
  |               | update_aad(...)          |
  |               v                          |
  |             +------------------+         |
  |             |                  |--+      |
  |             |       AAD        |  |      |
  |             |                  |<-+      |
  |             +------------------+         |
  |               |                          |
  | update(...)   | finish()                 | set_aad(...)
  |               v                          |
  |             +------------------+         |
  +-----------> |     Updating     | <-------+
                +------------------+
                         |
                         v
                        ...
  • update(...) path: The user encrypts or decrypts data without providing any AAD. This method is used to process the main body of the message. After processing the plaintext or ciphertext, the user can either continue updating with more data, or invoke finalize() to return the authentication tag.
  • set_aad path: Similar to the update(...) path, but this method sets the associated data (AAD), which is data that is authenticated but not encrypted. The AAD is processed first before transitioning to the Updating state, where data is encrypted or decrypted. AAD helps verify the integrity of the message.
  • update_aad(...) path: This method transitions to the AAD state, allowing the user to process associated data in chunks. It is useful in cases where the complete AAD is not available at once, and the user needs to progressively update it. Once all AAD is processed, the state transitions to Updating by invoking finish().

§Examples

use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};

let mut in_out = [7u8; 42];
let key = Key::new([3u8; 32]);

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
    .update_in_place(&mut in_out).opaque()?
    .finalize();

assert_ne!(in_out, [7u8; 42]);

let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
    .update_in_place(&mut in_out).opaque()?
    .finalize();

// PartialEq for tags is constant time
assert_eq!(tag, d_tag);
assert_eq!(in_out, [7u8; 42]);

With AAD

use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};

let mut in_out = [7u8; 42];
let key = Key::new([3u8; 32]);

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
    .set_aad("hello world").opaque()?
    .update_in_place(&mut in_out).opaque()?
    .finalize();

assert_ne!(in_out, [7u8; 42]);

let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
    .set_aad("hello world")
    .opaque_bind(|aead| aead.update_in_place(&mut in_out))
    .opaque_map(|aead| aead.finalize())?;

// PartialEq for tags is constant time
assert_eq!(tag, d_tag);
assert_eq!(in_out, [7u8; 42]);

§Errors

To guarantee that the state machine is correctly used, all methods take ownership over the ChaCha20Poly1305 instance. The ChaCha20Poly1305 instance is always returned whether the operation failed or not, allowing for retries.

For example, with the set_aad(...) method:

    Error!
  +----------+
  v          |
+--------------+  Success!   +----------------+
| set_aad(...) | ----------> | Updating State |
+--------------+             +----------------+

While this serves its purpose in allowing retries, it can be annoying for error propagation. To remedy this, there is the MakeOpaque trait, which will convert the error type into the Unspecified type via the opaque method, as well as provide common combinatorics such as opaque_bind and opaque_map.

Implementations§

Source§

impl ChaCha20Poly1305<Init>

Source

pub fn new<Mode: Updating>( key: impl GenericKey, iv: impl GenericIv<Size = U12>, ) -> ChaCha20Poly1305<Mode::InitState>

Create a new ChaCha20Poly1305 instance for either encryption or decryption.

§Generic

The provided Mode generic denotes whether this instance will be used for encryption or decryption. The possible types are:

  • Decrypt - Initialize the instance for decryption, there is also the new_decrypt convenience associated function.
  • Encrypt - Initialize the instance for encryption, there is also the new_encrypt convenience associated function.
§Arguments
  • key - The 32 byte key material to use.
  • iv - The 12 byte initialization vector to use.
§Examples

Decryption

use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Decrypt}, mac::poly1305::Key};

ChaCha20Poly1305::new::<Decrypt>(Key::new([7u8; 32]), [42u8; 12])

Encryption

use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Encrypt}, mac::poly1305::Key};

ChaCha20Poly1305::new::<Encrypt>(Key::new([7u8; 32]), [42u8; 12])
Source

pub fn new_encrypt<K, IV>( key: K, iv: IV, ) -> ChaCha20Poly1305<<Encrypt as Updating>::InitState>
where K: GenericKey, IV: GenericIv<Size = U12>,

Create a new ChaCha20Poly1305 instance for encryption.

§Arguments
  • key - The 32 byte key material to use.
  • iv - The 12 byte initialization vector to use.
§Example
use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};

ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
§Note

This is a convenience associated function for calling ChaCha20Poly1305::new::<Encrypt>(...), circumventing the need for importing the Encrypt marker type.

Source

pub fn new_decrypt<K, IV>( key: K, iv: IV, ) -> ChaCha20Poly1305<<Decrypt as Updating>::InitState>
where K: GenericKey, IV: GenericIv<Size = U12>,

Create a new ChaCha20Poly1305 instance for decryption.

§Arguments
  • key - The 32 byte key material to use.
  • iv - The 12 byte initialization vector to use.
§Example
use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key};

ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
§Note

This is a convenience associated function for calling ChaCha20Poly1305::new::<Decrypt>(...), circumventing the need for importing the Decrypt marker type.

Source§

impl<S: CanUpdateAad> ChaCha20Poly1305<S>

Source

pub const fn aad_io<IO>(self, io: IO) -> IoAad<S::Updating, IO>

Available on crate features std or embedded-io only.

Returns an Aad<S::Updating, IO> struct which implements the Read and Write traits for processing Additional Authenticated Data (AAD).

This method allows for streaming AAD processing, which is useful when the entire AAD is not available at once or when working with I/O streams.

§Arguments
  • io: An implementor of the Read or Write traits. The data passed to and from this io implementor will be authenticated as AAD.
§Returns

An Aad<S::Updating, IO> struct that wraps the ChaCha20Poly1305 instance and the provided IO type.

§Example
use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
use wolf_crypto::MakeOpaque;
use std::io::Write;

let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
let mut some_io_write_implementor = [7u8; 64];

let mut io = ChaCha20Poly1305::new_encrypt(key, iv)
    .aad_io(some_io_write_implementor.as_mut_slice());

let read = io.write(b"hello world")?;
let (aead, _my_writer) = io.finish();

assert_eq!(&some_io_write_implementor[..read], b"hello world");

let tag = aead.finalize();
Source

pub fn update_aad<A: Aad>( self, aad: A, ) -> Result<ChaCha20Poly1305<S::Updating>, Self>

Update the underlying message authentication code without encrypting the data.

This transitions to the streaming state for updating the AAD, allowing for partial updates. If you already have the entire AAD, consider using set_aad instead.

§Arguments
  • aad - The additional authenticated data to include in the authentication Tag.
§Errors

If the length of the AAD is greater than u32::MAX.

§Example
use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};

let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
    .update_aad("hello world").opaque()?
    .update_aad("!").opaque()?
    .finish()
    .finalize();

let d_tag = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
    .update_aad("hello world!").opaque()? // equivalent to processing in parts
    .finish()
    .finalize();

assert_eq!(tag, d_tag);
Source§

impl<S: CanUpdate> ChaCha20Poly1305<S>

Source

pub fn update_in_place( self, in_out: &mut [u8], ) -> Result<ChaCha20Poly1305<S::Mode>, Self>

Encrypt / Decrypt the provided in_out data in-place.

§Arguments
  • in_out - A mutable slice of data to be encrypted / decrypted in place.
§Errors

If the length of in_out is greater than u32::MAX.

§Example
use wolf_crypto::{aead::ChaCha20Poly1305, mac::poly1305::Key, MakeOpaque};

let mut in_out = [7u8; 42];
let key = Key::new([3u8; 32]);

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
    .set_aad("hello world").opaque()?
    .update_in_place(&mut in_out).opaque()?
    .finalize();

assert_ne!(in_out, [7u8; 42]);

let d_tag = ChaCha20Poly1305::new_decrypt(key.as_ref(), [7u8; 12])
    .set_aad("hello world")
    .opaque_bind(|aead| aead.update_in_place(&mut in_out))
    .opaque_map(|aead| aead.finalize())?;

assert_eq!(tag, d_tag);
assert_eq!(in_out, [7u8; 42]);
Source

pub fn update_in_place_sized<const C: usize>( self, in_out: &mut [u8; C], ) -> Result<ChaCha20Poly1305<S::Mode>, Self>

Encrypt / Decrypt the provided in_out data in-place.

This method is similar to update_in_place, but accepts a fixed-size array, allowing for potential optimizations and compile-time checks.

§Arguments
  • in_out - A mutable fixed-size array of data to be encrypted or decrypted in place.
§Errors

If the length of in_out is greater than u32::MAX.

§Example
use wolf_crypto::aead::{ChaCha20Poly1305};
use wolf_crypto::mac::poly1305::Key;
use wolf_crypto::MakeOpaque;

let mut data = [42u8; 64];
let key = Key::new([0u8; 32]);
let iv = [0u8; 12];

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
    .update_in_place_sized(&mut data).unwrap()
    .finalize();

assert_ne!(data, [42u8; 64]);

let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
    .update_in_place_sized(&mut data).unwrap()
    .finalize();

assert_eq!(data, [42u8; 64]);
assert_eq!(tag, d_tag);
Source

pub fn update( self, data: &[u8], output: &mut [u8], ) -> Result<ChaCha20Poly1305<S::Mode>, Self>

Encrypt / Decrypt the provided data into the output buffer.

§Arguments
  • data - A slice of data to be encrypted or decrypted.
  • output - A mutable slice where the result will be written. It must be at least as large as data.
§Errors
  • The length of data is greater than u32::MAX.
  • The output buffer is smaller than the data buffer.
§Example
use wolf_crypto::aead::{ChaCha20Poly1305};
use wolf_crypto::mac::poly1305::Key;
use wolf_crypto::MakeOpaque;

let data = [42u8; 64];
let mut out = [0u8; 64];
let key = Key::new([0u8; 32]);
let iv = [0u8; 12];

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
    .update(&data, &mut out).unwrap()
    .finalize();

assert_ne!(out, data);

let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
    .update_in_place(&mut out).unwrap()
    .finalize();

assert_eq!(out, data);
assert_eq!(tag, d_tag);
Source

pub const fn data_io<IO>(self, io: IO) -> IoData<S::Mode, IO>

Available on crate features std or embedded-io only.

Returns a Data<S::Mode, IO> struct which implements the Read trait for encrypting / decrypting data.

This method allows for streaming data processing, which is useful when working with large amounts of data or I/O streams.

§Arguments
  • io: An implementor of the Read trait. The data read from this io implementor will be encrypted or decrypted depending on the mode of the ChaCha20Poly1305 instance.
§Returns

A Data<S::Mode, IO> struct that wraps the ChaCha20Poly1305 instance and the provided IO type.

§Example
use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
use wolf_crypto::MakeOpaque;
use std::io::Read;

let (key, iv) = (Key::new([7u8; 32]), [42; 12]);
let plaintext = b"hello world";

// Encrypt
let mut encrypted = [0u8; 32];
let mut encrypt_io = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
    .data_io(&plaintext[..]);
let encrypted_len = encrypt_io.read(&mut encrypted)?;
let (aead, _) = encrypt_io.finish();
let tag = aead.finalize();

// Decrypt
let mut decrypted = [0u8; 32];
let mut decrypt_io = ChaCha20Poly1305::new_decrypt(key, iv)
    .data_io(&encrypted[..encrypted_len]);
let decrypted_len = decrypt_io.read(&mut decrypted)?;
let (aead, _) = decrypt_io.finish();
let decrypted_tag = aead.finalize();

assert_eq!(&decrypted[..decrypted_len], plaintext);
assert_eq!(tag, decrypted_tag);
Source§

impl<S: CanSetAad> ChaCha20Poly1305<S>

Source

pub fn set_aad<A: Aad>( self, aad: A, ) -> Result<ChaCha20Poly1305<<S as CanSetAad>::Mode>, Self>

Sets the Additional Authenticated Data (AAD) for the AEAD operation.

§Arguments
  • aad - The additional authenticated data to include in the authentication tag.
§Example
use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};

let key = Key::new([7u8; 32]);
let iv = [42u8; 12];

let aead = ChaCha20Poly1305::new_encrypt(key, iv)
    .set_aad("additional data").unwrap();
§Errors

If the length of the AAD is greater than u32::MAX.

§Notes
  • The AAD contributes to the authentication tag but is not part of the encrypted output.
  • If you need to provide the AAD in multiple parts, consider using update_aad instead.
Source§

impl<S: UpdatingAad> ChaCha20Poly1305<S>

Source

pub const fn finish(self) -> ChaCha20Poly1305<S::Mode>

Signals that no more Additional Authenticated Data (AAD) will be provided, transitioning the cipher to the data processing state.

This method finalizes the AAD input phase. After calling finish, you may finalize the state machine, or begin updating the cipher with data to be encrypted / decrypted.

§Example
use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};
use wolf_crypto::MakeOpaque;

let (key, iv) = (Key::new([7u8; 32]), [42; 12]);

let tag = ChaCha20Poly1305::new_encrypt(key, iv)
    .update_aad("additional ")
    .opaque_bind(|aead| aead.update_aad("data"))
    .opaque_bind(|aead| aead.update_aad("..."))
    .opaque_map(|aead| aead.finish())
     // (just use Poly1305 directly if you're doing this)
    .opaque_map(|aead| aead.finalize()).unwrap();
Source

pub fn update_aad_streaming<A: Aad>( &mut self, aad: A, ) -> Result<(), Unspecified>

Update the underlying message authentication code without encrypting the data or taking ownership of the ChaCha20Poly1305 instance.

This method is only available in the streaming state, making partial updates less of a hassle.

§Arguments
  • aad - The additional authenticated data to include in the authentication Tag.
§Errors

If the length of the AAD is greater than u32::MAX.

§Example
use wolf_crypto::{aead::chacha20_poly1305::{ChaCha20Poly1305, Key}, MakeOpaque};

let tag = ChaCha20Poly1305::new_encrypt(Key::new([7u8; 32]), [42u8; 12])
    .set_aad("hello world! Beautiful weather.")
    .opaque_map(|aead| aead.finalize())?;

let mut d_cipher = ChaCha20Poly1305::new_decrypt(Key::new([7u8; 32]), [42u8; 12])
    .update_aad("hello world").opaque()?;

// does not take ownership
d_cipher.update_aad_streaming("! ")?;
d_cipher.update_aad_streaming("Beautiful weather.")?;

let d_tag = d_cipher.finish().finalize();

assert_eq!(tag, d_tag);
Source§

impl<S: Updating> ChaCha20Poly1305<S>

Source

pub fn finalize(self) -> Tag

Finalizes the AEAD operation computing and returning the authentication Tag.

§Returns

The authentication Tag, resulting from the processed AAD and encryption / decryption operations.

§Security

On decryption, the returned Tag should be ensured to be equivalent to the Tag associated with the ciphertext. The decrypted ciphertext should not be trusted if the tags do not match.

Also, the comparison should not be done outside the Tag type, you must not call as_slice() or anything for the comparison. ALWAYS leverage the Tag’s PartialEq implementation.

§Example
use wolf_crypto::aead::chacha20_poly1305::{ChaCha20Poly1305, Key};

let key = Key::new([7u8; 32]);
let iv = [42u8; 12];
let mut data = [0u8; 64];

let tag = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
    .set_aad("additional data").unwrap()
    .update_in_place(&mut data).unwrap()
    .finalize();

// be sure to keep the tag around! important!

// On decryption, we **must** ensure that the resulting tag matches
// the provided tag.

let d_tag = ChaCha20Poly1305::new_decrypt(key, iv)
    .set_aad("additional data").unwrap()
    .update_in_place(&mut data).unwrap()
    .finalize();

assert_eq!(data, [0u8; 64]);

// most importantly!
assert_eq!(tag, d_tag);
Source

pub fn update_in_place_streaming<'io>( &mut self, in_out: &'io mut [u8], ) -> Result<&'io mut [u8], Unspecified>

Encrypt / Decrypt the provided in_out data in-place without taking ownership of the AEAD instance.

§Arguments
  • in_out - A mutable slice of data to be encrypted / decrypted in place.
§Returns

A reference to the updated in_out slice on success.

§Errors

Returns Unspecified if the length of in_out is greater than u32::MAX.

§Example
let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), [7u8; 12])
    .set_aad("hello world").opaque()?;

aead.update_in_place_streaming(&mut in_out1)?;
aead.update_in_place_streaming(&mut in_out2)?;

let tag = aead.finalize();

assert_ne!(in_out1, [7u8; 42]);
assert_ne!(in_out2, [8u8; 42]);
Source

pub fn update_streaming( &mut self, input: &[u8], output: &mut [u8], ) -> Result<(), Unspecified>

Encrypt / Decrypt the provided input data into the output buffer without taking ownership of the AEAD instance.

§Arguments
  • input - A slice of data to be encrypted / decrypted.
  • output - A mutable slice where the result will be written. It must be at least as large as input.
§Errors
  • The length of input is greater than u32::MAX.
  • The output buffer is smaller than the input buffer.
§Example
let mut aead = ChaCha20Poly1305::new_encrypt(key.as_ref(), iv)
    .set_aad("additional data").opaque()?;

aead.update_streaming(&data1, &mut out1)?;
aead.update_streaming(&data2, &mut out2)?;

let tag = aead.finalize();

assert_ne!(out1, data1);
assert_ne!(out2, data2);

Trait Implementations§

Source§

impl Debug for ChaCha20Poly1305<Init>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<Decrypt>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<DecryptAad>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<DecryptMaybeAad>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<Encrypt>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<EncryptAad>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Debug for ChaCha20Poly1305<EncryptMaybeAad>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<S> Freeze for ChaCha20Poly1305<S>

§

impl<S> RefUnwindSafe for ChaCha20Poly1305<S>
where S: RefUnwindSafe,

§

impl<S> Send for ChaCha20Poly1305<S>
where S: Send,

§

impl<S> Sync for ChaCha20Poly1305<S>
where S: Sync,

§

impl<S> Unpin for ChaCha20Poly1305<S>
where S: Unpin,

§

impl<S> UnwindSafe for ChaCha20Poly1305<S>
where S: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.