DKNet

DKNet.Svc.Encryption

Explicitly-invoked cryptography toolkit for .NET developers — AES-GCM and RSA encryption, RSA signing, HMAC and SHA hashing, and Base64/Base64URL helpers, all string-in/string-out.

[!NOTE] Looking for transparent EF Core column encryption instead — where an attribute on an entity property does the work automatically on save/load? That’s a different package: DKNet.EfCore.Encryption. Use DKNet.Svc.Encryption when you want to call Encrypt/Decrypt yourself at the point you call it; use DKNet.EfCore.Encryption when you want a column encrypted transparently, without the code that reads and writes the entity knowing. The two packages don’t share implementation.

✨ Why use it?

🚀 Quick Start

Use a .NET 10 console project. Install the package, then replace Program.cs with the example.

dotnet new console -f net10.0 -n EncDemo
cd EncDemo
dotnet add package DKNet.Svc.Encryption
dotnet add package Microsoft.Extensions.DependencyInjection
using DKNet.Svc.Encryption;
using DKNet.Svc.Encryption.Ciphers;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddEncryptionServices();                                   // IShaHashing, IHmacHashing
services.AddAesGcmEncryption(new AesGcmEncryption().Key);            // a throwaway demo key
using var provider = services.BuildServiceProvider();

var aesGcm = provider.GetRequiredService<IAesGcmEncryption>();
var package = aesGcm.EncryptString("4111-1111-1111-1111");
var plain = aesGcm.DecryptString(package);
Console.WriteLine(plain); // 4111-1111-1111-1111

Run with dotnet run. In a real application, source the key passed to AddAesGcmEncryption from configuration or a key vault — never a freshly generated one.

🏗️ Architecture

AddEncryptionServices registers the transient IShaHashing and IHmacHashing services with no key; AddAesGcmEncryption and AddRsaEncryption each register one key-bearing singleton cipher inside a boundary labelled "you supply and persist the key"; Base64StringExtensions is static and never registered.

Each registration call owns exactly one outcome: AddEncryptionServices always registers the two keyless hashing services; AddAesGcmEncryption and AddRsaEncryption each register one singleton cipher built from the key you pass in. Base64StringExtensions is a static extension class, never registered with DI. All three registration methods skip registration when the service type already exists, so calling any of them twice is a no-op — the first call’s key is the one the application keeps using.

🔄 How it works

AddAesGcmEncryption registers IAesGcmEncryption as a singleton; every EncryptString call produces a fresh nonce and tag, and DecryptString with the same associated data returns the plaintext while a mismatched associated data throws CryptographicException.

EncryptString and DecryptString run against the instance’s own key — no key argument needed once resolved. The diagram cannot show the per-call locking (AesGcmEncryption serializes Encrypt/Decrypt on the shared AesGcm handle) or that a hand-built new AesGcmEncryption() generates its own random key instead of using the one registered with DI. Each feature page below covers its own call path.

🧩 Features