ChaCha20.NetCore
2.0.0
dotnet add package ChaCha20.NetCore --version 2.0.0
NuGet\Install-Package ChaCha20.NetCore -Version 2.0.0
<PackageReference Include="ChaCha20.NetCore" Version="2.0.0" />
<PackageVersion Include="ChaCha20.NetCore" Version="2.0.0" />
<PackageReference Include="ChaCha20.NetCore" />
paket add ChaCha20.NetCore --version 2.0.0
#r "nuget: ChaCha20.NetCore, 2.0.0"
#:package ChaCha20.NetCore@2.0.0
#addin nuget:?package=ChaCha20.NetCore&version=2.0.0
#tool nuget:?package=ChaCha20.NetCore&version=2.0.0
ChaCha20.NetCore
ChaCha20.NetCore is a .NET implementation of the ChaCha20 stream cipher.
The implementation is optimized for secure memory handling and integrates with PinnedMemory to support memory-sensitive workflows.
This package provides ChaCha20 encryption/decryption only. It does not include authentication (for example, Poly1305).
Table of contents
- Requirements
- Installation
- Quick start
- API reference
- Usage notes
- Performance notes
- Security notes
- Validation and test vectors
- Development
- License
Requirements
- .NET 8 SDK for building/testing this repository.
- Target runtime/framework for the project: .NET 8.
The repository includes a global.json to pin the SDK family used for development.
Installation
NuGet Package Manager (CLI)
dotnet add package ChaCha20.NetCore
Package Manager Console
Install-Package ChaCha20.NetCore
NuGet Gallery
Quick start
using System;
using System.Security.Cryptography;
using ChaCha20.NetCore;
using PinnedMemory;
var nonce = RandomNumberGenerator.GetBytes(12); // RFC 8439 nonce size
var keyBytes = RandomNumberGenerator.GetBytes(32); // 256-bit key
var plaintext = new byte[] { 63, 61, 77, 20, 63, 61, 77, 20, 63, 61, 77 };
using var key = new PinnedMemory<byte>(keyBytes, false);
using var chacha20 = new ChaCha20(key, nonce); // default: 20 rounds
chacha20.UpdateBlock(plaintext, 0, plaintext.Length);
using var output = new PinnedMemory<byte>(new byte[chacha20.GetLength()]);
chacha20.DoFinal(output, 0);
var ciphertext = output.ToArray();
// ChaCha20 decrypts by applying the same keystream operation again
chacha20.Reset();
chacha20.UpdateBlock(ciphertext, 0, ciphertext.Length);
using var decrypted = new PinnedMemory<byte>(new byte[chacha20.GetLength()]);
chacha20.DoFinal(decrypted, 0);
API reference
ChaCha20
Constructor
ChaCha20(PinnedMemory<byte> key, byte[] nonce, int rounds = 20)
keymust be 32 bytes (256-bit).noncemust be 12 bytes (96-bit RFC 8439 nonce).roundsmust be positive and even (20 is standard ChaCha20).
Core members
int Rounds { get; }
int GetLength()
byte[] GetBuffer()
void Update(byte value)
void UpdateBlock(byte[] value, int offset, int length)
void UpdateBlock(PinnedMemory<byte> value, int offset, int length)
void DoFinal(byte[] output, int offset)
void DoFinal(PinnedMemory<byte> output, int offset)
void Reset()
void Dispose()
Behavior notes
GetLength()returns the current buffered input length in bytes.DoFinal(...)writes encrypted/decrypted output for the currently buffered input.Reset()clears buffered input and rewinds counter/index state to the initial position for the same key/nonce.Dispose()clears internal state and pinned buffers.
Usage notes
1) Never reuse a nonce with the same key
ChaCha20 is a stream cipher. Reusing (key, nonce) across different plaintexts can reveal relationships between messages.
2) Add authentication separately
ChaCha20 alone does not provide tamper detection. For authenticated encryption, pair with Poly1305 (ChaCha20-Poly1305) or use an AEAD library.
3) Treat keys as sensitive material
- Keep keys in pinned memory where practical.
- Dispose cipher instances promptly (
usingblocks). - Avoid logging keys, nonces, or raw plaintext in production diagnostics.
4) Use explicit framing for protocols
If you split messages across frames/chunks, ensure both sender and receiver agree on:
- nonce lifecycle
- message boundaries
- replay protections
- encoding/canonicalization of higher-level payloads
Performance notes
- The
DoFinal(byte[] output, int offset)path uses a SIMD-accelerated XOR routine when hardware vector support is available at runtime (Vector.IsHardwareAccelerated). - SIMD use is automatic and transparent; no extra configuration is required.
- A scalar fallback is always used when SIMD is unavailable or for any trailing bytes that do not fill a full vector width.
- The
DoFinal(PinnedMemory<byte> output, int offset)overload currently uses scalar writes.
Security notes
- ChaCha20 in this package follows RFC 8439 parameter conventions:
- 256-bit key (32 bytes)
- 96-bit nonce (12 bytes)
- 32-bit block counter
- This implementation enforces the ChaCha20 per-nonce processing limit and will throw if exceeded.
- Cryptographic integration should be reviewed against your protocol and threat model.
Validation and test vectors
The test project includes RFC 8439-focused verification, including keystream generation and roundtrip encryption/decryption behavior.
Run tests with:
dotnet test ChaCha20.NetCore.sln
Development
Build
dotnet build ChaCha20.NetCore.sln
Test
dotnet test ChaCha20.NetCore.sln
If dotnet is installed locally but not on PATH, invoke it explicitly:
$HOME/.dotnet/dotnet test ChaCha20.NetCore.sln
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- PinnedMemory (>= 2.0.1)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on ChaCha20.NetCore:
| Package | Downloads |
|---|---|
|
AeadChaCha20Poly1305.NetCore
Implementation of AEAD_CHACHA20_POLY1305 authenticated encryption with additional data using ChaCha20 and Poly1305, optimized for PinnedMemory and .NET. |
|
|
Poly1305ChaCha20.NetCore
Implementation of poly1305-dona message authentication code, designed by D. J. Bernstein with a chacha20 nonce. Optimized for PinnedMemory depends on ChaCha20.NetCore. |
GitHub repositories
This package is not used by any popular GitHub repositories.