Geralt
  • Introduction
  • Random data
  • Constant time
  • Secure memory
  • Encoding
  • Padding
  • Hashing
  • Message authentication
  • Password hashing
  • Key derivation
  • Authenticated encryption
    • Stream and file encryption
    • AEGIS-128L
    • AEGIS-256
    • ChaCha20-Poly1305
    • XChaCha20-Poly1305
  • Key exchange
  • Digital signatures
  • Advanced
    • Validation
    • Concat
    • ChaCha20
    • XChaCha20
    • HChaCha20
    • Poly1305
    • Ed25519 to X25519
Powered by GitBook
On this page
  • Purpose
  • Usage
  • IncrementalXChaCha20Poly1305
  • ChunkFlag
  • Push
  • Pull
  • Rekey
  • Reinitialize
  • Constants
  • Notes
  1. Authenticated encryption

Stream and file encryption

Last updated 6 months ago

Purpose

Encrypting streams and files should be done in chunks. This keeps memory usage low and detects corrupted chunks early. However, this is more complicated than one would expect because you need to prevent chunks from being removed, truncated, duplicated, and reordered.

This uses internally whilst handling these issues for you. Plaintext chunks can have different sizes, there is no practical stream length limit, associated data is supported, and rekeying is possible midway through encrypting the stream.

The optional associated data is useful for authenticating file headers, version numbers, timestamps, counters, and so on. It can be used to prevent and . It is not encrypted nor part of the ciphertext. It must be reproduceable or stored somewhere for decryption to be possible.

For file encryption, optimal chunk sizes include 16 KiB, 32 KiB, and 64 KiB. Pick one and use it for everything but the last chunk, which will likely be smaller.

Usage

IncrementalXChaCha20Poly1305

Initializes stream encryption or decryption using a key and header. For encryption, the header is filled with a random nonce. It MUST be sent/stored before the sequence of ciphertext messages because it is required to decrypt the stream.

using var secretstream = new IncrementalXChaCha20Poly1305(bool decryption, Span<byte> header, ReadOnlySpan<byte> key)

Exceptions

header has a length not equal to HeaderSize.

key has a length not equal to KeySize.

Error initializing.

ChunkFlag

Before encryption, a flag is attached to each chunk to provide information about that chunk:

  • ChunkFlag.Message: an ordinary plaintext chunk.

  • ChunkFlag.Boundary: the end of a set of messages but not the end of the stream.

  • ChunkFlag.Rekey: derive a new key after this chunk.

  • ChunkFlag.Final: the last plaintext chunk, marking the end of the stream.

For file encryption, ChunkFlag.Message and ChunkFlag.Final are the only flags required. For online communication, ChunkFlag.Boundary and ChunkFlag.Rekey may also be useful.

Push

Fills a span with the ciphertext chunk computed from a plaintext chunk and optional associated data. ChunkFlag.Final MUST be specified for the last plaintext chunk.

secretstream.Push(Span<byte> ciphertextChunk, ReadOnlySpan<byte> plaintextChunk, ReadOnlySpan<byte> associatedData = default, ChunkFlag chunkFlag = ChunkFlag.Message)

Exceptions

ciphertextChunk has a length not equal to plaintextChunk.Length + TagSize.

Cannot push into a decryption stream or push after ChunkFlag.Final.

The object has been disposed.

Encryption failed.

Pull

Verifies that the tag appended to the ciphertext chunk is correct for the given inputs. If verification fails, an exception is thrown. Otherwise, it fills a span with the decrypted ciphertext and returns the decrypted flag for that chunk.

var chunkFlag = secretstream.Pull(Span<byte> plaintextChunk, ReadOnlySpan<byte> ciphertextChunk, ReadOnlySpan<byte> associatedData = default)

Exceptions

plaintextChunk has a length not equal to ciphertextChunk.Length - TagSize.

Cannot pull from an encryption stream or pull after ChunkFlag.Final.

The object has been disposed.

Invalid authentication tag for the given inputs.

Rekey

Explicitly rekeys without storing the ChunkFlag.Rekey flag. For decryption, this function MUST be called at the same stream location to avoid an exception when decrypting the following chunk.

secretstream.Rekey()

Exceptions

Cannot rekey after ChunkFlag.Final.

The object has been disposed.

Reinitialize

Reinitializes stream encryption or decryption using a key and header. This avoids creating another using statement. For encryption, the header is filled with a random nonce. It MUST be sent/stored before the sequence of ciphertext messages because it is required to decrypt the stream.

secretstream.Reinitialize(bool decryption, Span<byte> header, ReadOnlySpan<byte> key)

Exceptions

header has a length not equal to HeaderSize.

key has a length not equal to KeySize.

The object has been disposed.

Error reinitializing.

Constants

These are used for validation and/or save you defining your own constants.

public const int KeySize = 32;
public const int HeaderSize = 24;
public const int TagSize = 17;

Notes

During decryption, you MUST check that the last chunk had the ChunkFlag.Final flag. Otherwise, you MUST throw a to detect stream truncation.

To detect stream truncation, if you reach the end of the stream and ChunkFlag.Final was not returned, you MUST throw a .

If you intend to feed multiple variable-length inputs into the associated data, beware of . Please read the page for more information.

The key MUST be uniformly random. It can either be or the output of a . Furthermore, it SHOULD be rotated periodically (e.g. a different key per file).

As a general rule, avoid compression before encryption. It can and has been the cause of .

high-level API
XChaCha20-Poly1305
confused deputy attacks
replay attacks
ArgumentOutOfRangeException
ArgumentOutOfRangeException
CryptographicException
CryptographicException
ArgumentOutOfRangeException
InvalidOperationException
ObjectDisposedException
CryptographicException
CryptographicException
ArgumentOutOfRangeException
InvalidOperationException
ObjectDisposedException
CryptographicException
InvalidOperationException
ObjectDisposedException
ArgumentOutOfRangeException
ArgumentOutOfRangeException
ObjectDisposedException
CryptographicException
canonicalization attacks
Concat
randomly generated
KDF
leak information
several attacks