PenguinConverters.Keyra.KeyStorageProvider.DpapiNg
3.3.5
dotnet add package PenguinConverters.Keyra.KeyStorageProvider.DpapiNg --version 3.3.5
NuGet\Install-Package PenguinConverters.Keyra.KeyStorageProvider.DpapiNg -Version 3.3.5
<PackageReference Include="PenguinConverters.Keyra.KeyStorageProvider.DpapiNg" Version="3.3.5" />
<PackageVersion Include="PenguinConverters.Keyra.KeyStorageProvider.DpapiNg" Version="3.3.5" />
<PackageReference Include="PenguinConverters.Keyra.KeyStorageProvider.DpapiNg" />
paket add PenguinConverters.Keyra.KeyStorageProvider.DpapiNg --version 3.3.5
#r "nuget: PenguinConverters.Keyra.KeyStorageProvider.DpapiNg, 3.3.5"
#:package PenguinConverters.Keyra.KeyStorageProvider.DpapiNg@3.3.5
#addin nuget:?package=PenguinConverters.Keyra.KeyStorageProvider.DpapiNg&version=3.3.5
#tool nuget:?package=PenguinConverters.Keyra.KeyStorageProvider.DpapiNg&version=3.3.5
PenguinConverters.Keyra.KeyStorageProvider.DpapiNg
DPAPI-NG based KeyStorageProvider using AES-256-GCM encryption for Keyra vaults.
Overview
This provider uses Windows Data Protection API - Next Generation (DPAPI-NG) for protecting AES-256 encryption keys. It provides authenticated encryption with AES-GCM and supports the Keyra authenticator chain for multi-factor key protection.
┌─────────────────────────────────────────────────────────────────┐
│ DPAPI-NG Key Protection Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ AES-256 Key (32 bytes) │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Password factor (optional - provider property) │ │
│ │ • Chain credential (KDF recipe: Argon2id/HKDF/HMAC) │ │
│ │ • Argon2id KEK derived in the Rust engine │ │
│ │ • AES key XOR KEK before DPAPI-NG protection │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ DPAPI-NG (NCryptProtectSecret) │ │
│ │ • SID-based protection descriptor │ │
│ │ • Tied to Windows user/machine │ │
│ │ • TPM-backed when available │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Protected Key Blob (unified .key file) │
│ │
└─────────────────────────────────────────────────────────────────┘
Package Information
| Property | Value |
|---|---|
| Package ID | PenguinConverters.Keyra.KeyStorageProvider.DpapiNg |
| Target Framework | net8.0 |
| Platform | Windows (requires DPAPI-NG) |
| Dependencies | Keyra.Core, CandyStore |
AES-256-GCM Encryption
Secrets are encrypted using AES-256 in GCM (Galois/Counter Mode) for authenticated encryption.
┌─────────────────────────────────────────────────────────────────┐
│ AES-GCM Security Parameters │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Key Size: 256 bits (32 bytes) - AES-256 │
│ Nonce Size: 96 bits (12 bytes) - Optimal for GCM │
│ Tag Size: 128 bits (16 bytes) - Maximum integrity │
│ │
│ Ciphertext Format: │
│ ┌──────────┬───────────────────────┬──────────┐ │
│ │ Nonce │ Ciphertext │ Tag │ │
│ │ 12 bytes │ (variable) │ 16 bytes │ │
│ └──────────┴───────────────────────┴──────────┘ │
│ │
│ CRITICAL: Nonce is generated randomly for EACH encryption │
│ using RandomNumberGenerator (cryptographically │
│ secure) to ensure uniqueness. │
│ │
└─────────────────────────────────────────────────────────────────┘
Key Generation
The provider supports extensible key generation through the IKeyGenerator interface.
┌─────────────────────────────────────────────────────────────────┐
│ Key Generation System │
├─────────────────────────────────────────────────────────────────┤
│ │
│ IKeyGenerator Interface: │
│ ├── DisplayName (UI display) │
│ ├── Description (User-facing description) │
│ ├── RequiresUserInput (needs UI interaction?) │
│ ├── KeySizeBytes (32 for AES-256) │
│ └── GenerateKey() (returns 32-byte key) │
│ │
│ Built-in Generators: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ RandomKeyGenerator (default) │ │
│ │ • Uses RandomNumberGenerator.Create() │ │
│ │ • Cryptographically secure random bytes │ │
│ │ • No user input required │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Future extensibility: │
│ • PasswordDerivedKeyGenerator (Argon2id from user password) │
│ • HardwareDerivedKeyGenerator (TPM/HSM integration) │
│ │
└─────────────────────────────────────────────────────────────────┘
DPAPI-NG Protection Descriptors
┌─────────────────────────────────────────────────────────────────┐
│ Protection Descriptor Options │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Current User (default): │
│ "SID=S-1-5-21-..." │
│ Only the current user can decrypt │
│ │
│ Local Machine: │
│ "LOCAL=machine" │
│ Any user on this machine can decrypt │
│ │
│ Multiple Users/Groups: │
│ "SID=S-1-5-21-... OR SID=S-1-5-21-..." │
│ Any of the specified SIDs can decrypt │
│ │
└─────────────────────────────────────────────────────────────────┘
Storage Format
Key File (unified .key)
All key storage providers share the unified .key extension. The owning provider is
identified by the providerTypeId field, never by the file name.
{
"keyId": "keyra.a1b2c3d4e5f67890...",
"protectedBlob": "BASE64_ENCODED_DPAPI_NG_BLOB",
"createdUtc": "2025-01-20T12:00:00Z",
"algorithm": "AES-256-GCM",
"version": 1,
"providerTypeId": "dpapi-ng"
}
Encrypted Secret (Base64)
[Nonce: 12 bytes][Ciphertext: variable][Tag: 16 bytes]
Usage
Creating a New Key
using PenguinConverters.Keyra.KeyStorageProvider.DpapiNg;
// Create provider
Provider provider = new Provider
{
Identifier = @"C:\Vaults\production"
};
// Generate key with authenticator chain password
SecureString password = await authenticatorChain.DeriveKeyAsync(isNew: true);
IKey key = provider.GenerateKey(password);
// Key is now protected and stored as a unified .key file
Loading an Existing Key
// Load key using authenticator chain
SecureString password = await authenticatorChain.DeriveKeyAsync(isNew: false);
IKey key = provider.FindKeyByIdentifier("keyra.a1b2c3d4...", password);
Encrypting/Decrypting Secrets
// Encrypt a secret
SecureString plaintext = "my-secret-value".ToSecureString();
string ciphertext = key.Encrypt(plaintext); // Base64 output
// Decrypt a secret
SecureString decrypted = key.Decrypt(ciphertext);
Security Considerations
Nonce Management
- CRITICAL: Never reuse a nonce with the same key
- RandomNumberGenerator ensures cryptographic randomness
- 2^96 possible nonces makes collision extremely unlikely
Key Protection Layers
- DPAPI-NG: Windows-managed protection tied to user/machine
- Authenticator Chain: Multi-factor XOR protection (Password, YubiKey)
- Memory Clearing: Keys zeroed on Dispose using CryptographicOperations.ZeroMemory
Authentication Tag
- 128-bit tag provides maximum GCM integrity protection
- Any tampering with ciphertext will cause decryption to fail
Project Structure
PenguinConverters.Keyra.KeyStorageProvider.DpapiNg/
├── Provider.cs # IProvider implementation
├── Key.cs # IKey with AES-GCM encrypt/decrypt
├── Configuration.cs # Provider settings
├── ProviderBuilder.cs # Builder pattern
├── AesGcmCrypto.cs # AES-GCM helpers
├── DpapiNgProtection.cs # DPAPI-NG + password protection
├── KeyMetadata.cs # unified .key file structure
└── Generators/
└── RandomKeyGenerator.cs # Default key generator
Comparison with the AES-GCM Provider
| Feature | AES-GCM Provider | DPAPI-NG Provider |
|---|---|---|
| Secret encryption | AES-256-GCM (Rust engine) | AES-256-GCM (Rust engine) |
| Key protection | the portable password scheme (Argon2id KEK + AES-GCM, Rust end to end) | NCrypt, with an optional Argon2id-KEK XOR password factor |
| Key storage | unified .key file (providerTypeId: "aes-gcm") |
unified .key file (providerTypeId: "dpapi-ng") |
| OS identity binding | None (password only) | Windows user / AD SID via protection descriptor |
| Portability | Cross-platform | Windows only (a descriptor-less export through a fresh instance produces the portable password scheme, tagged aes-gcm; an instance that opened a dpapi-ng key keeps its binding on every re-protect - issue #454) |
License
Proprietary - PenguinConverters
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows7.0
- PenguinConverters.CandyStore (>= 3.3.5)
- PenguinConverters.Keyra.Core (>= 3.3.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.3.5 | 54 | 10/5/2026 |
| 3.3.3 | 61 | 10/4/2026 |
| 3.3.1 | 51 | 10/1/2026 |
| 3.3.0 | 83 | 9/28/2026 |
| 3.2.0 | 82 | 9/28/2026 |
| 3.1.2 | 97 | 9/23/2026 |
| 3.1.1.9 | 89 | 9/23/2026 |
| 3.1.1.8 | 90 | 9/22/2026 |
| 3.1.1 | 91 | 9/21/2026 |
| 3.0.0 | 111 | 9/11/2026 |
| 2.23.7 | 108 | 9/7/2026 |
| 2.23.5 | 99 | 9/7/2026 |
| 2.23.3 | 104 | 9/7/2026 |
| 2.22.0 | 103 | 9/1/2026 |
| 2.21.0 | 104 | 8/31/2026 |
| 2.20.0 | 94 | 8/31/2026 |
| 2.19.2 | 98 | 8/28/2026 |
| 2.19.0 | 108 | 8/19/2026 |
| 2.18.0 | 109 | 8/18/2026 |
| 2.17.0 | 113 | 8/17/2026 |