PenguinConverters.Keyra
3.3.5
dotnet add package PenguinConverters.Keyra --version 3.3.5
NuGet\Install-Package PenguinConverters.Keyra -Version 3.3.5
<PackageReference Include="PenguinConverters.Keyra" Version="3.3.5" />
<PackageVersion Include="PenguinConverters.Keyra" Version="3.3.5" />
<PackageReference Include="PenguinConverters.Keyra" />
paket add PenguinConverters.Keyra --version 3.3.5
#r "nuget: PenguinConverters.Keyra, 3.3.5"
#:package PenguinConverters.Keyra@3.3.5
#addin nuget:?package=PenguinConverters.Keyra&version=3.3.5
#tool nuget:?package=PenguinConverters.Keyra&version=3.3.5
PenguinConverters.Keyra
Developer SDK for integrating Keyra encryption and decryption into applications.
Overview
The Keyra SDK provides a minimal, high-level API for encrypting and decrypting secrets using Keyra key packages. It wraps the Core infrastructure with a fluent builder pattern and automatic provider discovery, so developers don't need to interact with key storage providers directly.
┌─────────────────────────────────────────────────────────────────────┐
│ Keyra SDK │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ DecryptorBuilder │ │
│ │ │ │
│ │ .UseKeyFile(path) // .keyra | share file | key.json | │ │
│ │ // vault.json / vault directory │ │
│ │ .UseShare(text) // KEYRA: ... :ARYEK in memory │ │
│ │ .WithPassword("password") Auto-discovers │ │
│ │ .Build() ───► IPortableKeyLoader │ │
│ │ via reflection │ │
│ └──────────────────────┬───────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Decryptor │ │
│ │ │ │
│ │ .Encrypt("plaintext") → "BASE64_CIPHERTEXT" │ │
│ │ .Decrypt("ciphertext") → char[] │ │
│ │ .KeyId → "key-identifier" │ │
│ │ .Dispose() → Cleans up key resources │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Settings.Secret │ │
│ │ │ │
│ │ .Value = "encrypted_or_plain" │ │
│ │ .Protected = true/false │ │
│ │ .TryGetValue(decryptor, out plaintext) │ │
│ │ Secret.Protect(decryptor, plaintext) → protected node │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Package Information
| Property | Value |
|---|---|
| Package ID | PenguinConverters.Keyra |
| Target Framework | net8.0 |
| Platform | Cross-platform |
| Dependencies | PenguinConverters.Keyra.Core, Microsoft.Extensions.Logging.Abstractions |
Quick Start
using PenguinConverters.Keyra;
// Load a key and create a decryptor
using Decryptor decryptor = new DecryptorBuilder()
.UseKeyFile("path/to/vault.key.keyra")
.WithPassword("myPassword")
.Build();
// Encrypt
string ciphertext = decryptor.Encrypt("my secret value");
// Decrypt
char[] plaintext = decryptor.Decrypt(ciphertext);
string result = new string(plaintext);
Array.Clear(plaintext); // Clear sensitive data from memory
API Reference
DecryptorBuilder
Fluent builder for creating Decryptor instances. Handles key file loading, provider discovery, and package extraction.
public class DecryptorBuilder
{
// Set path to the key source. Content decides how it is read - the file
// name and extension carry no meaning. Accepts: a .keyra package as the
// raw ZIP or as armored text (KEYRA: ... :ARYEK), a raw key document
// (key.json / .key), or a vault directory / its vault.json (loads the
// sibling key.json).
DecryptorBuilder UseKeyFile(string filePath);
// Set an armored vault share held in memory (env var, cloud secret
// store, CI secret) instead of a file.
DecryptorBuilder UseShare(string armoredShare);
// Set password for the key
DecryptorBuilder WithPassword(string password);
// Register a custom key loader (optional, bypasses auto-discovery)
DecryptorBuilder UseKeyLoader(IPortableKeyLoader loader);
// Build the Decryptor (loads key, discovers provider)
Decryptor Build();
}
Auto-Discovery: When Build() is called, the builder scans all loaded assemblies via reflection for types implementing IPortableKeyLoader. Dispatch to a loader uses the providerTypeId the key records about itself — never a file name or extension. This means you only need the provider assembly referenced — no manual registration.
Package Support: .keyra files are ZIP archives containing the key document. The builder transparently extracts and reads the key from the package. An armored share (the KEYRA: ... :ARYEK text the desktop app puts on the clipboard when sharing a vault — plain or decoratively shaped) decodes to the same package and is accepted anywhere a package is: saved to a file for UseKeyFile, or passed as text to UseShare.
Decryptor
Provides simple encrypt/decrypt operations, backed either by a native vault session (portable
AES-GCM keys — the master key stays inside the Rust engine) or by the value cipher
(ISecretCipher) of a .NET-unwrapped key (DPAPI-NG). No crypto call touches an IKey directly.
public class Decryptor : IDisposable
{
// Unique key identifier
string KeyId { get; }
// Encrypt plaintext to BASE64-encoded ciphertext
string Encrypt(string plaintext);
string Encrypt(char[] plaintext);
// Decrypt BASE64-encoded ciphertext to char array
char[] Decrypt(string ciphertext);
// Dispose key resources
void Dispose();
}
Settings.Secret
Configuration class for storing secret values that may be encrypted. Useful for application settings that need deferred decryption.
The node deserializes cleanly from JSON configuration ({"Value": "...", "Protected": true}), so a config POCO can declare Secret properties directly.
public class Secret
{
// The stored value (plaintext or ciphertext)
string Value { get; set; }
// Whether the value is encrypted
bool Protected { get; set; }
// Decrypt and retrieve the value. A Protected value with no decryption
// available fails - it is never surfaced as if it were plaintext.
bool TryGetValue(Decryptor decryptor, out char[] plaintext);
bool TryGetValue(Func<string, char[]> decrypt, out char[] plaintext);
// Static null-safe helper
static bool TryGetValue(Secret value, Func<string, char[]> decrypt, out char[] plaintext);
// Create nodes
static Secret Protect(Decryptor decryptor, char[] plaintext);
static Secret Protect(Decryptor decryptor, string plaintext);
static Secret FromPlaintext(string value);
}
Usage Patterns
Encrypt and Decrypt
using Decryptor decryptor = new DecryptorBuilder()
.UseKeyFile("vault.key.keyra")
.WithPassword("password")
.Build();
string ciphertext = decryptor.Encrypt("SuperSecret123!");
char[] plaintext = decryptor.Decrypt(ciphertext);
Key from a Saved Share or Vault Directory
// The armored share text the desktop app copies to the clipboard when
// sharing a vault, saved to a file at a secure location:
using Decryptor fromShareFile = new DecryptorBuilder()
.UseKeyFile(@"D:\secure\myapp.key.keyra") // KEYRA: ... :ARYEK
.WithPassword("password")
.Build();
// The same share held in an environment variable or cloud secret store:
using Decryptor fromShareText = new DecryptorBuilder()
.UseShare(Environment.GetEnvironmentVariable("MYAPP_KEYRA_SHARE")!)
.WithPassword("password")
.Build();
// A vault laid out on disk (vault.json + key.json):
using Decryptor fromVault = new DecryptorBuilder()
.UseKeyFile(@"C:\keyra\vaults\myvault\vault.json") // or the directory
.WithPassword("password")
.Build();
Protected Configuration Entries
// Protect once (e.g. in a setup tool) and store the node in configuration:
Secret dbPassword = Secret.Protect(decryptor, "SuperSecret123!");
File.WriteAllText("appsettings.secrets.json", JsonSerializer.Serialize(dbPassword));
// At runtime: deserialize and disclose only when needed
Secret node = JsonSerializer.Deserialize<Secret>(File.ReadAllText("appsettings.secrets.json"))!;
if (node.TryGetValue(decryptor, out char[] password))
{
string connectionString = $"Password={new string(password)}";
Array.Clear(password);
}
Custom Key Loader
IPortableKeyLoader customLoader = new MyCustomKeyLoader();
using Decryptor decryptor = new DecryptorBuilder()
.UseKeyFile("key.custom")
.WithPassword("password")
.UseKeyLoader(customLoader)
.Build();
Working with Key Packages
// A .keyra package is a ZIP, or the armored text of one; the builder reads either
using Decryptor decryptor = new DecryptorBuilder()
.UseKeyFile("vault.key.keyra") // the package's key.json holds the key
.WithPassword("password")
.Build();
Console.WriteLine($"Key ID: {decryptor.KeyId}");
Addressing a vault
VaultRepository.OpenVault(name, ...) resolves by display name, which anyone with the desktop
app can change. VaultRepository.OpenVaultById(vaultId, ...) resolves by the vault's immutable
id (keyra.<32 hex>), which nothing changes for the life of the vault.
Use the name for something a person just typed; use the id for anything you store. GetVaults()
returns both as VaultInfo, and VaultSession.VaultId gives the id of an open vault.
string vaultId = repository.GetVaults().Single(v => v.Name == "Prod").VaultId;
// ... keep vaultId in config; it survives a rename
using VaultSession session = repository.OpenVaultById(vaultId, password);
SDK vs Core
| Feature | Core | SDK |
|---|---|---|
Key interfaces (IKey, IPortableKeyLoader) |
Direct access | Wrapped |
| Provider discovery | Manual | Automatic via reflection |
| Package (.keyra) handling | Basic Package class |
Integrated in builder |
| Encrypt/decrypt | Via IKey methods |
Simple string/char[] API |
| Password handling | SecureString required |
String accepted, converted internally |
| Builder pattern | Limited | Full fluent API |
| Configuration secrets | Not provided | Settings.Secret class |
Supported Key Providers
The SDK discovers key providers at runtime. Available providers:
| Provider | File Extension | providerTypeId |
Package |
|---|---|---|---|
| DPAPI-NG | .key |
dpapi-ng |
PenguinConverters.Keyra.KeyStorageProvider.DpapiNg |
| AES-GCM | .key |
aes-gcm |
PenguinConverters.Keyra.KeyStorageProvider.AesGcm |
All key storage providers use the unified .key file extension. The provider that owns a
key file is identified by the providerTypeId field inside the key's JSON metadata, never by
the file extension. To use a provider, reference its NuGet package. The SDK will discover it
automatically.
NuGet Installation
From nuget.org (once the packages are published there — the nuget-publish-nugetorg release
job): no source configuration at all, dotnet add package PenguinConverters.Keyra just works.
From the internal GitLab registry (pre-release / internal builds): the packages are also
published to the Keyra project's GitLab NuGet registry. Register it once
(authenticate with a personal access token or deploy token that has read_api / registry read
scope):
dotnet nuget add source "http://gitlab.penguinconverters.net/api/v4/projects/2/packages/nuget/index.json" \
--name keyra --username <token-name> --password <token> \
--store-password-in-clear-text --allow-insecure-connections
--allow-insecure-connections is required because the instance serves plain HTTP — NuGet
refuses HTTP sources without it.
Then install the SDK and, for provider-backed keys, a key storage provider:
dotnet add package PenguinConverters.Keyra
# Windows / Active Directory vaults:
dotnet add package PenguinConverters.Keyra.KeyStorageProvider.DpapiNg
# Portable password keys via a provider (the engine also opens aes-gcm keys without one):
dotnet add package PenguinConverters.Keyra.KeyStorageProvider.AesGcm
PenguinConverters.CandyStore (pulled in transitively) carries the native Keyra engine as
per-RID runtime assets (win-x64, win-x86, linux-x64) — no separate native install step.
License
Proprietary - Penguin Converters
| 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
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.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 | 50 | 10/5/2026 |
| 3.3.3 | 65 | 10/4/2026 |
| 3.3.1 | 77 | 10/1/2026 |
| 3.3.0 | 81 | 9/28/2026 |
| 3.2.0 | 79 | 9/28/2026 |
| 3.1.2 | 94 | 9/23/2026 |
| 3.1.1.9 | 97 | 9/23/2026 |
| 3.1.1.8 | 99 | 9/22/2026 |
| 3.1.1 | 89 | 9/21/2026 |
| 3.0.0 | 107 | 9/11/2026 |
| 2.23.7 | 112 | 9/7/2026 |
| 2.23.5 | 99 | 9/7/2026 |
| 2.23.3 | 108 | 9/7/2026 |
| 2.22.0 | 113 | 9/1/2026 |
| 2.21.0 | 108 | 8/31/2026 |
| 2.20.0 | 105 | 8/31/2026 |
| 2.19.2 | 169 | 8/28/2026 |
| 2.19.0 | 202 | 8/19/2026 |
| 2.18.0 | 106 | 8/18/2026 |
| 2.17.0 | 113 | 8/17/2026 |