Security.SecretProtector
1.0.1
See the version list below for details.
dotnet add package Security.SecretProtector --version 1.0.1
NuGet\Install-Package Security.SecretProtector -Version 1.0.1
<PackageReference Include="Security.SecretProtector" Version="1.0.1" />
<PackageVersion Include="Security.SecretProtector" Version="1.0.1" />
<PackageReference Include="Security.SecretProtector" />
paket add Security.SecretProtector --version 1.0.1
#r "nuget: Security.SecretProtector, 1.0.1"
#:package Security.SecretProtector@1.0.1
#addin nuget:?package=Security.SecretProtector&version=1.0.1
#tool nuget:?package=Security.SecretProtector&version=1.0.1
Security.SecretProtector
AES-256-GCM at-rest secret protection for multi-tenant SaaS services. One audited implementation, shared across services, with a fixed on-disk format so stored secrets keep decrypting across upgrades.
Consolidates two previously-duplicated copies:
- AML's
AesGcmCredentialCipher(external-provider API keys, webhook signing secrets) - Kefi's
ConfigAesGcmSecretProtector(per-tenant Stripe credentials)
Surface
public interface ISecretProtector
{
string Protect(string plaintext); // → base64( nonce(12) ‖ tag(16) ‖ ciphertext )
string Unprotect(string token); // throws on tamper / wrong key / not configured
bool IsConfigured { get; } // false in soft mode when the key is unset
}
On-disk format (stable — do not change)
A protected token is base64( nonce(12 bytes) ‖ tag(16 bytes) ‖ ciphertext ). AES-256-GCM
authenticated encryption: a tampered or wrong-key token throws on Unprotect rather than
returning garbage. The key is a 32-byte value decoded from base64 or hex (hex is
detected first for 64-char all-hex strings). Rotating the key invalidates every stored
ciphertext, so the key is catastrophic-if-lost.
Quick start
Register the protector, pointing it at the configuration key that holds your 32-byte key:
using Security.SecretProtector.Extensions;
// Mandatory secret → fail fast at startup if the key is missing/invalid (Kefi style):
builder.Services.AddConfigSecretProtector("KEFI_SECRETS_ENC_KEY", failFast: true);
// Optional secret → soft mode; ISecretProtector.IsConfigured gates callers (AML style):
builder.Services.AddConfigSecretProtector("Providers:CredentialKey", failFast: false);
Then consume it:
public sealed class MyService(ISecretProtector protector)
{
public string Store(string apiKey) => protector.Protect(apiKey);
public string? Use(string ciphertext)
=> protector.IsConfigured ? protector.Unprotect(ciphertext) : null;
}
The key value lives only in the app's runtime configuration / secret (env var in dev,
Kubernetes secret in prod) — never in this package or any committed file. Generate one with
openssl rand -base64 32.
Modes
| Mode | failFast |
Missing / invalid key | Use when |
|---|---|---|---|
| Fail-fast | true (default) |
throws at construction/startup | the secret is mandatory |
| Soft | false |
IsConfigured == false; Protect/Unprotect throw only if called |
the secret is optional |
License
MIT
| 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
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Security.SecretProtector:
| Package | Downloads |
|---|---|
|
Dloizides.Webhooks.AspNetCore
Durable outbound-webhook delivery for multi-tenant ASP.NET Core SaaS. A per-endpoint transactional outbox: each (event x subscribed endpoint) is delivered and retried independently on its own back-off, so one failing endpoint never re-delivers to healthy ones. HMAC-signed POSTs with configurable headers, scale-out-safe xmin lease processor, dead-lettering, and per-attempt delivery history. The consumer plugs in an endpoint resolver + their DbContext; delivery moves off the request path in ~5 lines of Program.cs. |
GitHub repositories
This package is not used by any popular GitHub repositories.