Enigma.DataEncryption
1.1.0
dotnet add package Enigma.DataEncryption --version 1.1.0
NuGet\Install-Package Enigma.DataEncryption -Version 1.1.0
<PackageReference Include="Enigma.DataEncryption" Version="1.1.0" />
<PackageVersion Include="Enigma.DataEncryption" Version="1.1.0" />
<PackageReference Include="Enigma.DataEncryption" />
paket add Enigma.DataEncryption --version 1.1.0
#r "nuget: Enigma.DataEncryption, 1.1.0"
#:package Enigma.DataEncryption@1.1.0
#addin nuget:?package=Enigma.DataEncryption&version=1.1.0
#tool nuget:?package=Enigma.DataEncryption&version=1.1.0
Enigma.DataEncryption
Enigma.DataEncryption encrypts arbitrary data and streams into a self-describing binary container — a header carrying everything a reader needs to decrypt, followed by an AEAD payload. The whole surface follows one idiom: pick the service that matches your credential — a password, an RSA key pair, a post-quantum ML-KEM key pair, or both key pairs together — then hand it an input stream, an output stream and that credential. Each service derives, transports or combines a 32-byte data key and encrypts the payload with a 256-bit cipher in GCM mode, writing the salt, costs and cipher choice into the header, so decryption needs nothing but the container and the credential. It is built on Enigma.Core, which supplies every cryptographic primitive; BouncyCastle backs Enigma.Core but never appears on this library's public surface.
What's new in 1.1 — now built on Enigma.Core 1.1.0, raising the BouncyCastle.Cryptography floor to 2.7.0. No API change and no format change: every container written by 1.0.0 decrypts unchanged. See RELEASENOTES.md.
Features
- Password-based encryption —
IPbkdf2DataEncryptionService(PBKDF2-HMAC-SHA256) andIArgon2DataEncryptionService(Argon2id v1.3, memory-hard and recommended for new work), each taking abyte[]orchar[]password and writing its cost parameters into the header. - RSA encryption —
IRsaDataEncryptionServicetransports the data key under RSAES-OAEP with a selectable padding hash (SHA-256, SHA-384 or SHA-512; SHA-1 rejected), recorded in the header so the reader needs no hash argument. Takes PEM-encoded keys directly, including password-protected private-key PEMs. - Post-quantum ML-KEM encryption —
IMLKemDataEncryptionServiceestablishes the data key by ML-KEM key encapsulation (FIPS 203) at parameter set 512, 768 or 1024. - True RSA + ML-KEM hybrid —
IHybridDataEncryptionServicetransports a secret under each primitive and combines both into the data key with a split-key PRF, so a container stays secure as long as either primitive holds. Breaking RSA with a quantum computer is not enough, and neither is a classical break of ML-KEM. Both private keys are required to decrypt. - Four AEAD ciphers — AES-256, Twofish-256, Serpent-256 and Camellia-256, each in GCM mode, chosen per
call through the
Cipherenum. - An authenticated header — the complete header is passed as GCM associated data, so editing any byte of it, the cipher and iteration count included, is an authentication failure rather than a weaker decryption. A 16-byte key-confirmation tag gives fast, uniform wrong-credential detection before a payload byte is read, and makes the construction key-committing, which plain GCM is not.
- Bounded hostile input — every cost and length field read from a header is checked against
DataEncryptionLimitsbefore any allocation or key derivation, so the cost of decrypting a container is capped by the reader, not dictated by whoever wrote it. Pass stricter limits to any decrypt call. - Header inspection without decryption —
IEncryptedDataInspectorreturns a parsedEncryptedDataHeaderwith no credential at all, for detect-then-dispatch and for gating on cost. - File-path helpers — fourteen
DataEncryptionFileExtensionswrappers over the five methods, which open asynchronousFileStreams, create or overwrite the output, and delete a partial output on any failure. - Dependency injection in one call —
AddEnigmaDataEncryption()registers all six services as singletons viaTryAdd, so any registration can be overridden.
Asynchronous, cancellable, observable
Every operation is async and takes an optional IProgress<int> reporting payload bytes processed, plus a
CancellationToken. Nothing is buffered whole: encrypting a multi-gigabyte file costs the same memory as
encrypting a short string. All six services are stateless and safe for concurrent use, so one instance can
be shared across an application.
Installation
dotnet add package Enigma.DataEncryption
Targets .NET Standard 2.0, .NET 8.0, and .NET 10.0; built on Enigma.Core 1.1.0.
Quick start
Encrypt a stream under a password with Argon2id and AES-256-GCM, then read it back — the cost parameters and salt travel in the container, so decryption takes only the password:
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Enigma.DataEncryption;
IArgon2DataEncryptionService service = new Argon2DataEncryptionService();
char[] password = "correct horse battery staple".ToCharArray();
using MemoryStream input = new(Encoding.UTF8.GetBytes("Attack at dawn."));
using MemoryStream container = new();
await service.EncryptAsync(input, container, Cipher.Aes256Gcm, password);
container.Position = 0;
using MemoryStream recovered = new();
await service.DecryptAsync(container, recovered, password);
Console.WriteLine(Encoding.UTF8.GetString(recovered.ToArray())); // Attack at dawn.
Documentation
Per-category guides — each with the supported operations, the key types, and copy-pasteable C# samples
verified against the public API — live under docs/guides/ in the repository, indexed by
docs/guides/README.md. They cover password-based encryption, RSA, ML-KEM, the RSA + ML-KEM hybrid, header
inspection, file operations, and dependency injection. The normative specification of the container format — every offset,
size and constant, the header-authentication rule, the key-confirmation construction, the limits and the
error mapping — is docs/format.md, also in the repository.
License
Enigma.DataEncryption is released under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
- System.Buffers (>= 4.6.1)
-
net10.0
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
-
net8.0
- Enigma.Core (>= 1.1.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.18)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
A dependency release. Built on Enigma.Core 1.1.0, which raises the BouncyCastle.Cryptography floor to 2.7.0 — consumers pinned to 2.6.x must upgrade. No public API was added, removed or changed, and the target frameworks are unchanged (netstandard2.0, net8.0, net10.0). The container format is untouched: format version 0x10, every header shape identical, so every container written by 1.0.0 decrypts unchanged — verified against the 24 containers committed as 1.0.0-era test fixtures. One behaviour changed with the upgrade: a PEM whose Base64 is invalid now raises ArgumentException naming the offending parameter, where 1.0.0 raised a bare FormatException, which is preserved as a nested inner exception. The documented contract is unchanged — docs/format.md §9 always permitted either type — so this is not a breaking change, but code catching FormatException alone should be widened. Microsoft.Extensions.DependencyInjection.Abstractions is deliberately held at 9.0.18. See RELEASENOTES.md for the full details.