Module orion::aead::streaming

source ·
Available on crate feature safe_api only.
Expand description

Streaming AEAD based on XChaCha20Poly1305.

Use case:

This can be used to encrypt and authenticate a stream of data. It prevents the modification, reordering, dropping or duplication of messages. Nonce management is handled automatically.

An example of this could be the encryption of files that are too large to encrypt in one piece.


This implementation is based on and compatible with the “secretstream” API of libsodium.


  • secret_key: The secret key.
  • nonce: The nonce value.
  • plaintext: The data to be encrypted.
  • ciphertext: The encrypted data with a Poly1305 tag and a StreamTag indicating its function.
  • tag: Indicates the type of message. The tag is a part of the output when encrypting. It is encrypted and authenticated.


An error will be returned if:

  • secret_key is not 32 bytes.
  • The length of ciphertext is not at least ABYTES.
  • The received mac does not match the calculated mac when decrypting. This can indicate a dropped or reordered message within the stream.
  • More than 2^32-3 * 64 bytes of data are processed when encrypting/decrypting a single chunk.
  • ABYTES + plaintext.len() overflows when encrypting.


A panic will occur if:

  • 64 + (ciphertext.len() - ABYTES) overflows when decrypting.
  • Failure to generate random bytes securely.


  • It is critical for security that a given nonce is not re-used with a given key.
  • To securely generate a strong key, use SecretKey::generate().
  • The length of the messages is leaked.
  • It is recommended to use StreamTag::Finish as tag for the last message. This allows the decrypting side to detect if messages at the end of the stream are lost.


use orion::aead::streaming::*;
use orion::aead::SecretKey;

let chunk_size: usize = 128; // The size of the chunks you wish to split the stream into.
let src = [255u8; 4096]; // Some example input stream.
let mut out: Vec<Vec<u8>> = Vec::with_capacity(4096 / 128);

let secret_key = SecretKey::default();

// Encryption:
let (mut sealer, nonce) = StreamSealer::new(&secret_key)?;

for (n_chunk, src_chunk) in src.chunks(chunk_size).enumerate() {
    let encrypted_chunk =
        if src_chunk.len() != chunk_size || n_chunk + 1 == src.len() / chunk_size {
            // We've reached the end of the input source,
            // so we mark it with the Finish tag.
            sealer.seal_chunk(src_chunk, &StreamTag::Finish)?
        } else {
            // Just a normal chunk
            sealer.seal_chunk(src_chunk, &StreamTag::Message)?
    // Save the encrypted chunk somewhere

// Decryption:
let mut opener = StreamOpener::new(&secret_key, &nonce)?;

for (n_chunk, src_chunk) in out.iter().enumerate() {
    let (_decrypted_chunk, tag) = opener.open_chunk(src_chunk)?;

    if src_chunk.len() != chunk_size + ABYTES || n_chunk + 1 == out.len() {
        // We've reached the end of the input source,
        // so we check if the last chunk is also set as Finish.
        assert_eq!(tag, StreamTag::Finish, "Stream has been truncated!");


pub use crate::hazardous::aead::streaming::Nonce;
pub use crate::hazardous::aead::streaming::StreamTag;
pub use crate::hazardous::aead::streaming::ABYTES;


Streaming authenticated decryption.
Streaming authenticated encryption.