Lyo.KeyStore
3.0.0
dotnet add package Lyo.KeyStore --version 3.0.0
NuGet\Install-Package Lyo.KeyStore -Version 3.0.0
<PackageReference Include="Lyo.KeyStore" Version="3.0.0" />
<PackageVersion Include="Lyo.KeyStore" Version="3.0.0" />
<PackageReference Include="Lyo.KeyStore" />
paket add Lyo.KeyStore --version 3.0.0
#r "nuget: Lyo.KeyStore, 3.0.0"
#:package Lyo.KeyStore@3.0.0
#addin nuget:?package=Lyo.KeyStore&version=3.0.0
#tool nuget:?package=Lyo.KeyStore&version=3.0.0
Lyo.KeyStore
Key encryption key (KEK) storage and rotation contracts for Lyo.Encryption. Encryption services call IKeyStore by keyId and optional version
string so ciphertext can outlive a single key-material rotation.
Vocabulary: the KEK lives in the store. Data encryption keys (DEKs) used by envelope / two-key flows are generated per operation by the encryption layer and are not persisted in the keystore. Only the KEK that wraps them is stored.
Examples
Register with DI
using Lyo.KeyStore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
// Unkeyed
services.AddLocalKeyStore(ks =>
{
ks.UpdateKeyFromString("app", configuration["Encryption:CurrentKek"]!);
});
// Keyed (pair with AddEncryptionServiceKeyed / addon *ServiceKeyed)
const string storeKey = "primary";
services.AddKeyedLocalKeyStore(storeKey, ks =>
{
ks.AddKeyFromString("app", "v1", configuration["Encryption:Kek:v1"]!);
ks.SetCurrentVersion("app", "v1");
});
Register with DI (2)
{
"Encryption": {
"CurrentKek": "replace-in-user-secrets",
"Kek": {
"v1": "versioned-secret"
}
}
}
IKeyStore methods
Versions are strings, for example "1", "2025-01", or opaque ids from an HSM. GetCurrentVersion returns the version used when callers omit an explicit version on encrypt.
| Concern | Members |
|---|---|
| Read material | GetKey, GetKeyAsync, GetCurrentKey, GetCurrentKeyAsync |
| Read version pointer | GetCurrentVersion, GetCurrentVersionAsync |
| Write / rotate | AddKey, AddKeyAsync, AddKeyFromString, AddKeyFromStringAsync, SetCurrentVersion, SetCurrentVersionAsync, UpdateKey, UpdateKeyAsync, UpdateKeyFromString, UpdateKeyFromStringAsync |
| Existence | HasKey, HasKeyAsync |
| Metadata | GetKeyMetadata, SetKeyMetadata, async variants; GetSaltForVersion when derivation salts are tracked per version |
UpdateKey* allocates a new version, monotonic in LocalKeyStore, and sets it current. Use this for rotation. AddKey pins an exact (keyId, version) pair. Use that when
importing known version labels from another system.
Exceptions
Failures surface as KeyNotFoundException, InvalidKeyException, KeyVersionNotFoundException, all rooted at EncryptionKeyException. Log with keyId. Never log raw key bytes.
Pair with metrics so silent misconfiguration does not look like bad client data.
Key derivation (KeyDerivation/)
HKDF (RFC 5869), PBKDF2-SHA256 helpers, and Argon2 adapters live in this assembly so onboarding UIs can derive stable bytes from passphrases consistently with AddKeyFromString.
Prefer SecureKeyGenerator when generating random material instead of ad-hoc RNG.
Implementations of IKeyDerivationService:
| Service | Notes |
|---|---|
Pbkdf2KeyDerivationService |
PBKDF2 (SHA-256 by default). Iteration count and output length are configurable. |
HkdfKeyDerivationService |
HKDF-Extract + HKDF-Expand (SHA-256 by default). Derives sub-keys from existing key material. |
Argon2KeyDerivationService |
Argon2id with configurable memory / parallelism / time-cost via constructor parameters (BouncyCastle on netstandard2.0). |
Key validation (KeyValidator)
ValidateKeyOrThrow(byte[] keyMaterial, ISymmetricKeyMaterialSize spec). Rejects null/empty buffers and key lengths that aren't in the algorithm's accepted set.IsValid(...)/TryValidate(...). Non-throwing variants for UIs that report validation failures inline.- Optional entropy/heuristic checks (e.g. all-zero buffers, repeating patterns) so that obviously bad imports fail early.
Inventory (IKeyInventoryStore)
Optional capability for admin UIs and audits: enumerate logical keyIds and versions. Not every store implements listing. Probe for IKeyInventoryStore or your cloud-specific API
before assuming discovery works. KeyStoreMigrator requires it on the source.
Copying a store (KeyStoreMigrator)
KeyStoreMigrator.CopyAsync copies every version of the given key ids from a source that implements IKeyInventoryStore onto another IKeyStore. CopyInventoryAsync does that
for every id the source lists, including keys no file uses. Both take an optional IProgress<KeyStoreMigrationProgress>. Null reports nothing. Each report is one version after it
is verified: copied, skipped, or failed.
The copy uses AddKey, so version strings stay the ones already written into ciphertext ("1", "v1", "2025-01"). A destination version with the same bytes is skipped.
Different bytes throw before AddKey overwrites them. The destination current pointer is set to the source pointer only when the destination had no pointer, or already pointed at
the same version. A different pointer throws and is left where it was. After AddKey, the destination GetKey must match the source bytes or the copy stops before
SetCurrentVersion.
FileStorageTransfer in Lyo.FileStorage calls CopyAsync for the key ids a transfer actually references. Use CopyInventoryAsync when the whole store should move.
Dependency injection
| Extension | Registers |
|---|---|
AddLocalKeyStore() |
LocalKeyStore + unkeyed IKeyStore |
AddLocalKeyStore(Action<LocalKeyStore> configure) |
Configured LocalKeyStore + unkeyed IKeyStore |
AddKeyedLocalKeyStore(string key, Action<LocalKeyStore> configure) |
Per-key LocalKeyStore + IKeyStore |
Configuration uses the configure => lambda. There is no AddLocalKeyStoreFromConfiguration. Read IConfiguration inside configure, the same pattern as other Lyo libraries:
Example appsettings.json values consumed manually in configure:
Local development (LocalKeyStore)
In-memory store for tests and local apps:
services.AddLocalKeyStore(ks =>
{
ks.AddKeyFromString("app", "v1", "local-dev-secret");
ks.SetCurrentVersion("app", "v1");
});
AddKeyedLocalKeyStore registers distinct LocalKeyStore instances per DI key. Useful when a single process hosts multiple logical tenants, if you are careful about keyed
resolution and never cross-wire IKeyStore instances.
LocalKeyStore.RemoveKey(string keyId, string version) retires a non-current version and returns false when the version doesn't exist or matches GetCurrentVersion. Call
SetCurrentVersion before pruning the previous current.
Production. LocalKeyStore is not durable and not audited. Swap for Lyo.KeyStore.Aws, Azure Key Vault, PKCS#11, or another IKeyStore that meets your retention and access
policies.
Cloud bridge
See Lyo.KeyStore.Aws for AwsKeyStore and helpers that align with AWS Secrets Manager style payloads.
How encryption uses the store
Symmetric and envelope services resolve keyId on encrypt. Ciphertext and stream headers carry keyId and version so decrypt can call GetKey(keyId, version) even after
rotation. Two-key flows wrap per-operation DEKs. KEK rotation can use ReEncryptDek on ITwoKeyEncryptionService without re-encrypting bulk payload. See the encryption README.
Operational checklist
- Thread safety. Custom stores must tolerate concurrent
Get*while adminsAdd*/SetCurrentVersion. - Rotation. Keep old versions until all ciphertext referencing them is re-encrypted or retired. Track
GetCurrentVersionseparately from the newest encrypt version. - Backups. Database and blob snapshots do not replace key governance. Export and access control live in infra policy.
- Configuration. Prefer environment-specific
keyIdnamespaces (tenant:prod:comic-files) to avoid accidental cross-environment decrypt.
Dependency injection
Microsoft.Extensions.DependencyInjection.Extensions in this package: AddLocalKeyStore() registers a shared LocalKeyStore as IKeyStore.
AddLocalKeyStore(Action<LocalKeyStore>) configures keys before the container finishes building. Keyed encryption registration lives in
EncryptionServiceExtensions, for example AddEncryptionServiceKeyed. See also
Lyo.Encryption/README.md.
Encryption guide
Algorithm choice, stream formats, threat modeling, and long-form examples remain in ../README.md, the folder-level encryption guide.
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Common.Core(direct, lyo)Lyo.Exceptions(direct, lyo)Konscious.Security.Cryptography.Argon21.3.1(direct, third-party)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5(direct, microsoft, net10.0, netstandard2.0)Microsoft.Bcl.AsyncInterfaces10.0.5(transitive, microsoft, netstandard2.0)System.Memory4.6.3(transitive, microsoft, netstandard2.0)System.Text.Json10.0.5(transitive, microsoft, netstandard2.0)
| 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 was computed. 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
- Konscious.Security.Cryptography.Argon2 (>= 1.3.1)
- Lyo.Common.Core (>= 3.0.0)
- Lyo.Exceptions (>= 3.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
-
net10.0
- Konscious.Security.Cryptography.Argon2 (>= 1.3.1)
- Lyo.Common.Core (>= 3.0.0)
- Lyo.Exceptions (>= 3.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
NuGet packages (9)
Showing the top 5 NuGet packages that depend on Lyo.KeyStore:
| Package | Downloads |
|---|---|
|
Lyo.Encryption
A production-ready .NET encryption library providing secure, authenticated encryption with support for multiple algorithms (AES-GCM, ChaCha20Poly1305, RSA), key management, and envelope encryption patterns. |
|
|
Lyo.FileStorage
File storage service interface and base implementation for file operations. |
|
|
Lyo.Authentication
Server-side authentication services for Lyo: Ed25519-signed JWT issuance/validation (`ILyoJwtIssuer`, `Ed25519LyoJwtIssuer`, `JwkSetBuilder`), opaque Format-B token issuance/validation/store (`IApiTokenIssuer`, `IApiTokenStore`, `ApiTokenCodec` minting/hashing), refresh-token exchange, user/external-identity stores, scope registry runtime, and audit recorder plumbing. Pure data shapes (records, claim names, format helpers, audit-event taxonomy, `Scope`) live in `Lyo.Authentication.Models` and are consumer-safe. This package brings in `Lyo.KeyStore`, `Lyo.Hashing`, and BouncyCastle — do not reference it from a Blazor WebAssembly client. |
|
|
Lyo.KeyStore.Aws
AWS Secrets Manager implementation of the Lyo KeyStore interface for production key management. |
|
|
Lyo.Config.Api
Central HTTP API exposing Lyo.Config PostgreSQL-backed IConfigStore for microservices (polling-friendly ETags). Embed via AddConfigApi / MapConfigApiEndpoints. |
GitHub repositories
This package is not used by any popular GitHub repositories.