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
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
StreamThe stream containing encrypted data. It must begin with the secret stream header written during encryption.
output
StreamThe 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
, orkey
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
StreamThe readable stream containing encrypted data. The stream must begin with the encryption header produced during the corresponding encryption process.
output
StreamThe 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
StreamA readable stream containing the encrypted data. The stream must begin with the encryption header.
output
StreamThe 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
CancellationTokenOptional 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
StreamA readable stream containing encrypted data. The stream must begin with the header produced during encryption.
output
StreamThe 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
CancellationTokenOptional 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
StreamThe readable stream containing plaintext to encrypt.
output
StreamThe 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
, oroutput
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
StreamThe readable stream containing plaintext to encrypt.
output
StreamThe 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
StreamThe readable stream containing plaintext to encrypt.
output
StreamThe 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
CancellationTokenOptional 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
StreamThe readable stream containing plaintext to encrypt.
output
StreamThe 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
CancellationTokenOptional 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.