pub struct ChaCha20Poly1305<S: State = Init> { /* private fields */ }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 invokefinalize()to return the authentication tag.set_aadpath: Similar to theupdate(...)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 theUpdatingstate, where data is encrypted or decrypted. AAD helps verify the integrity of the message.update_aad(...)path: This method transitions to theAADstate, 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 toUpdatingby invokingfinish().
§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>
impl ChaCha20Poly1305<Init>
Sourcepub fn new<Mode: Updating>(
key: impl GenericKey,
iv: impl GenericIv<Size = U12>,
) -> ChaCha20Poly1305<Mode::InitState>
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 thenew_decryptconvenience associated function.Encrypt- Initialize the instance for encryption, there is also thenew_encryptconvenience 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])Sourcepub fn new_encrypt<K, IV>(
key: K,
iv: IV,
) -> ChaCha20Poly1305<<Encrypt as Updating>::InitState>
pub fn new_encrypt<K, IV>( key: K, iv: IV, ) -> ChaCha20Poly1305<<Encrypt as Updating>::InitState>
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.
Sourcepub fn new_decrypt<K, IV>(
key: K,
iv: IV,
) -> ChaCha20Poly1305<<Decrypt as Updating>::InitState>
pub fn new_decrypt<K, IV>( key: K, iv: IV, ) -> ChaCha20Poly1305<<Decrypt as Updating>::InitState>
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>
impl<S: CanUpdateAad> ChaCha20Poly1305<S>
Sourcepub const fn aad_io<IO>(self, io: IO) -> IoAad<S::Updating, IO> ⓘ
Available on crate features std or embedded-io only.
pub const fn aad_io<IO>(self, io: IO) -> IoAad<S::Updating, IO> ⓘ
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 theReadorWritetraits. The data passed to and from thisioimplementor 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();Sourcepub fn update_aad<A: Aad>(
self,
aad: A,
) -> Result<ChaCha20Poly1305<S::Updating>, Self>
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 authenticationTag.
§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>
impl<S: CanUpdate> ChaCha20Poly1305<S>
Sourcepub fn update_in_place(
self,
in_out: &mut [u8],
) -> Result<ChaCha20Poly1305<S::Mode>, Self>
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]);Sourcepub fn update_in_place_sized<const C: usize>(
self,
in_out: &mut [u8; C],
) -> Result<ChaCha20Poly1305<S::Mode>, Self>
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);Sourcepub fn update(
self,
data: &[u8],
output: &mut [u8],
) -> Result<ChaCha20Poly1305<S::Mode>, Self>
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 asdata.
§Errors
- The length of
datais greater thanu32::MAX. - The
outputbuffer is smaller than thedatabuffer.
§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);Sourcepub const fn data_io<IO>(self, io: IO) -> IoData<S::Mode, IO> ⓘ
Available on crate features std or embedded-io only.
pub const fn data_io<IO>(self, io: IO) -> IoData<S::Mode, IO> ⓘ
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 theReadtrait. The data read from thisioimplementor 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>
impl<S: CanSetAad> ChaCha20Poly1305<S>
Sourcepub fn set_aad<A: Aad>(
self,
aad: A,
) -> Result<ChaCha20Poly1305<<S as CanSetAad>::Mode>, Self>
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_aadinstead.
Source§impl<S: UpdatingAad> ChaCha20Poly1305<S>
impl<S: UpdatingAad> ChaCha20Poly1305<S>
Sourcepub const fn finish(self) -> ChaCha20Poly1305<S::Mode>
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();Sourcepub fn update_aad_streaming<A: Aad>(
&mut self,
aad: A,
) -> Result<(), Unspecified>
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 authenticationTag.
§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>
impl<S: Updating> ChaCha20Poly1305<S>
Sourcepub fn finalize(self) -> Tag
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);Sourcepub fn update_in_place_streaming<'io>(
&mut self,
in_out: &'io mut [u8],
) -> Result<&'io mut [u8], Unspecified>
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]);Sourcepub fn update_streaming(
&mut self,
input: &[u8],
output: &mut [u8],
) -> Result<(), Unspecified>
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 asinput.
§Errors
- The length of
inputis greater thanu32::MAX. - The
outputbuffer is smaller than theinputbuffer.
§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);