Table of Contents

Class SecretStream

Namespace
LibSodium
Assembly
LibSodium.Net.dll

Provides high-level, stream-based authenticated encryption and decryption using the XChaCha20-Poly1305 algorithm. This class abstracts the complexity of securely processing large data streams, including chunking, authentication, and cryptographic state management.

public static class SecretStream
Inheritance
SecretStream
Inherited Members

Remarks

This class is built on LibSodium’s crypto_secretstream_xchacha20poly1305 API, using XChaCha20 for encryption and Poly1305 for message authentication. The large 192-bit nonce (24 bytes) virtually eliminates the risk of nonce reuse when generated randomly.

The stream is processed in fixed-size chunks (64 KB), each individually encrypted and authenticated. A randomly generated header (nonce and metadata) is prepended to the stream and required for successful decryption.

Security Considerations:

  • Key Management: Keys must be generated securely and stored safely. Compromise of the key invalidates confidentiality and integrity guarantees.
  • Nonce Handling: Nonces are generated internally. Do not reuse headers or keys manually unless you know what you're doing.
  • Integrity: Poly1305 tags ensure tampering is detected during decryption. Any modification will result in decryption failure.

Fields

PlainChunkSize

The size of each plaintext chunk processed during encryption (64KB). This chunk size is used to divide the input stream into manageable blocks.

public const int PlainChunkSize = 65536

Field Value

int

Methods

Decrypt(Stream, Stream, SecureMemory<byte>)

Synchronously decrypts data from the input stream using a key stored in secure memory, and writes the plaintext to the output stream.

public static void Decrypt(Stream input, Stream output, SecureMemory<byte> key)

Parameters

input Stream

The stream containing encrypted data. It must begin with the secret stream header written during encryption.

output Stream

The stream where decrypted plaintext will be written.

key SecureMemory<byte>

A SecureMemory<T> buffer containing the decryption key. This key must match the one used to encrypt the stream.

Remarks

This method behaves identically to Decrypt(Stream, Stream, ReadOnlySpan<byte>), but uses a secure memory buffer for enhanced key confidentiality.

The decryption header is consumed automatically at the beginning of the stream. Chunks are processed sequentially, and any failure in tag verification will cause decryption to halt with an exception.

Internal buffers are cleared and returned to the pool after use. The input and output streams remain open.

Exceptions

ArgumentNullException

Thrown if input, output, or key is null.

ObjectDisposedException

Thrown if the secure memory key has already been disposed.

EndOfStreamException

Thrown if the stream ends before the Final tag is encountered.

LibSodiumException

Thrown if the authentication of a chunk fails, which indicates tampering or a mismatched key.

Decrypt(Stream, Stream, ReadOnlySpan<byte>)

Synchronously decrypts data from the input stream and writes the plaintext to the output stream, verifying each chunk's authenticity using XChaCha20-Poly1305.

public static void Decrypt(Stream input, Stream output, ReadOnlySpan<byte> key)

Parameters

input Stream

The readable stream containing encrypted data. The stream must begin with the encryption header produced during the corresponding encryption process.

output Stream

The writable stream where decrypted plaintext will be written.

key ReadOnlySpan<byte>

The secret decryption key. It must match the key used to encrypt the stream and be exactly 32 bytes long.

Remarks

This method processes the encrypted stream in chunks, validating each chunk before decrypting it. If authentication fails, a LibSodiumException is thrown and the decrypted output is invalidated.

The stream must start with a header containing the nonce and metadata necessary for decryption. This header is automatically consumed at the beginning of the stream.

All internal buffers are zeroed after use. The input and output streams are not closed automatically.

Exceptions

ArgumentException

Thrown if the key is invalid.

EndOfStreamException

Thrown if the stream ends before the Final tag is reached, indicating an incomplete or truncated stream.

LibSodiumException

Thrown if authentication fails, indicating the ciphertext has been tampered with or the wrong key was used.

DecryptAsync(Stream, Stream, SecureMemory<byte>, CancellationToken)

Asynchronously decrypts data from the input stream using a key stored in SecureMemory<T>, and writes the plaintext to the output stream.

public static Task DecryptAsync(Stream input, Stream output, SecureMemory<byte> key, CancellationToken cancellationToken = default)

Parameters

input Stream

A readable stream containing the encrypted data. The stream must begin with the encryption header.

output Stream

The writable stream where the decrypted plaintext will be written.

key SecureMemory<byte>

A secure memory buffer containing the decryption key. This must match the key used to encrypt the stream.

cancellationToken CancellationToken

Optional token to cancel the asynchronous operation.

Returns

Task

A task representing the asynchronous decryption process.

Remarks

This overload behaves identically to DecryptAsync(Stream, Stream, ReadOnlyMemory<byte>, CancellationToken), but uses a SecureMemory<T> buffer for enhanced runtime key protection.

The key is securely wiped from memory once decryption is complete. Stream lifetime is not managed automatically.

Exceptions

ArgumentNullException

Thrown if any argument is null.

ObjectDisposedException

Thrown if the secure key has already been disposed.

EndOfStreamException

Thrown if the stream ends before the final tag is reached.

LibSodiumException

Thrown if the integrity check fails (e.g., if the ciphertext has been tampered with).

OperationCanceledException

Thrown if the operation is canceled.

DecryptAsync(Stream, Stream, ReadOnlyMemory<byte>, CancellationToken)

Asynchronously decrypts data from the input stream and writes the plaintext to the output stream, verifying integrity using XChaCha20-Poly1305.

public static Task DecryptAsync(Stream input, Stream output, ReadOnlyMemory<byte> key, CancellationToken cancellationToken = default)

Parameters

input Stream

A readable stream containing encrypted data. The stream must begin with the header produced during encryption.

output Stream

The writable stream where decrypted plaintext will be written.

key ReadOnlyMemory<byte>

The secret key used for decryption. It must match the key used during encryption.

cancellationToken CancellationToken

Optional token to cancel the asynchronous operation.

Returns

Task

A task representing the asynchronous decryption process.

Remarks

The decryption process begins by reading the stream header, which includes a nonce required to initialize the decryption state. Each encrypted chunk is then read, authenticated, and decrypted in order.

If any chunk fails authentication, a LibSodiumException is thrown and no plaintext is written for that chunk. If the stream ends before encountering a chunk tagged as Final, an EndOfStreamException is thrown.

This method uses pooled buffers and zeroes out internal state after use to reduce memory leakage risks. Input and output streams are not closed automatically.

Exceptions

ArgumentNullException

Thrown if any argument is null.

EndOfStreamException

Thrown if the stream ends unexpectedly or the final tag is never reached.

LibSodiumException

Thrown if the integrity check fails on any chunk (i.e., authentication tag mismatch).

OperationCanceledException

Thrown if the operation is canceled.

Encrypt(Stream, Stream, SecureMemory<byte>)

Synchronously encrypts data from the input stream using a secure key, and writes the ciphertext to the output stream.

public static void Encrypt(Stream input, Stream output, SecureMemory<byte> key)

Parameters

input Stream

The readable stream containing plaintext to encrypt.

output Stream

The writable stream where ciphertext will be written.

key SecureMemory<byte>

A SecureMemory<T> buffer containing the encryption key. It must be 32 bytes in size, and will be securely wiped from memory after use.

Remarks

This method is functionally equivalent to Encrypt(Stream, Stream, ReadOnlySpan<byte>), but accepts the encryption key wrapped in SecureMemory<T> for added in-memory protection.

This improves resistance to key leakage through memory inspection, especially in long-lived processes.

Exceptions

ArgumentNullException

Thrown if key, input, or output is null.

ObjectDisposedException

Thrown if the key has already been disposed.

ArgumentException

Thrown if the key is invalid (wrong length).

Encrypt(Stream, Stream, ReadOnlySpan<byte>)

Synchronously encrypts data from the input stream and writes the ciphertext to the output stream using the XChaCha20-Poly1305 algorithm.

public static void Encrypt(Stream input, Stream output, ReadOnlySpan<byte> key)

Parameters

input Stream

The readable stream containing plaintext to encrypt.

output Stream

The writable stream where ciphertext will be written.

key ReadOnlySpan<byte>

The encryption key. Must be securely generated and exactly 32 bytes long for XChaCha20-Poly1305.

Remarks

This method performs stream encryption in-place and blocks the calling thread until completion. It is suitable for scenarios where asynchronous patterns are not required or not supported.

The input is processed in chunks of PlainChunkSize bytes. Each chunk is encrypted and authenticated before being written to the output stream. A cryptographic header is written at the beginning, and a final tag is written after the last chunk.

All internal buffers are zeroed after use, and pooled memory is returned. The input and output streams are not closed or disposed automatically.

Exceptions

ArgumentException

Thrown if the key is invalid.

EndOfStreamException

Thrown if the input stream ends unexpectedly.

EncryptAsync(Stream, Stream, SecureMemory<byte>, CancellationToken)

Asynchronously encrypts data from the input stream using a key stored in SecureMemory<T> and writes the ciphertext to the output stream.

public static Task EncryptAsync(Stream input, Stream output, SecureMemory<byte> key, CancellationToken cancellationToken = default)

Parameters

input Stream

The readable stream containing plaintext to encrypt.

output Stream

The writable stream where ciphertext will be written.

key SecureMemory<byte>

A secure memory buffer containing the secret key. It is critical that this buffer is disposed properly to ensure the key is wiped from memory.

cancellationToken CancellationToken

Optional token to cancel the asynchronous operation.

Returns

Task

A task representing the asynchronous encryption process.

Remarks

This overload offers identical functionality to EncryptAsync(Stream, Stream, ReadOnlyMemory<byte>, CancellationToken), but uses a SecureMemory<T> buffer to enhance key security during runtime.

Using secure memory reduces the risk of sensitive data being captured in memory dumps or accessed by unauthorized code.

Exceptions

ArgumentNullException

Thrown if any argument is null.

ObjectDisposedException

Thrown if the secure key has already been disposed.

OperationCanceledException

Thrown if the operation is canceled.

EncryptAsync(Stream, Stream, ReadOnlyMemory<byte>, CancellationToken)

Asynchronously encrypts data from the input stream and writes the ciphertext to the output stream using the XChaCha20-Poly1305 algorithm.

public static Task EncryptAsync(Stream input, Stream output, ReadOnlyMemory<byte> key, CancellationToken cancellationToken = default)

Parameters

input Stream

The readable stream containing plaintext to encrypt.

output Stream

The writable stream where ciphertext will be written.

key ReadOnlyMemory<byte>

The secret key for encryption. Must be securely generated and kept confidential. Typically 32 bytes in length for XChaCha20-Poly1305.

cancellationToken CancellationToken

Optional token to cancel the asynchronous operation.

Returns

Task

A task representing the asynchronous encryption process.

Remarks

The input stream is read in PlainChunkSize blocks. Each block is encrypted and written to the output stream with an authentication tag to ensure integrity.

A cryptographic header (including a randomly generated nonce) is prepended to the output. This header is required for successful decryption.

The encryption state is maintained internally and finalized when the last chunk is written with the Final tag.

Note: The caller is responsible for managing the lifetime of the input/output streams. They are not closed or disposed automatically.

Exceptions

ArgumentNullException

Thrown if any argument is null.

OperationCanceledException

Thrown if the operation is canceled.