PenguinConverters.Keyra 3.3.5

dotnet add package PenguinConverters.Keyra --version 3.3.5
                    
NuGet\Install-Package PenguinConverters.Keyra -Version 3.3.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PenguinConverters.Keyra" Version="3.3.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PenguinConverters.Keyra" Version="3.3.5" />
                    
Directory.Packages.props
<PackageReference Include="PenguinConverters.Keyra" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PenguinConverters.Keyra --version 3.3.5
                    
#r "nuget: PenguinConverters.Keyra, 3.3.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PenguinConverters.Keyra@3.3.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PenguinConverters.Keyra&version=3.3.5
                    
Install as a Cake Addin
#tool nuget:?package=PenguinConverters.Keyra&version=3.3.5
                    
Install as a Cake Tool

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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