encryptman-keyring 0.1.1

OS keychain-backed master key storage for encryptman
Documentation

encryptman-keyring

Crates.io Documentation License

OS keychain-backed master key storage for encryptman.

Features

  • Zero file management — master key stored in OS keychain, no .key files on disk
  • Cross-platform — Windows Credential Manager, macOS Keychain, Linux Secret Service
  • One-call setupVault::new("my-app") generates or loads the key automatically
  • File migrationVault::migrate_from_file() imports existing key files and deletes them
  • Domain isolation — service name used as HKDF context for encryptman
  • Secure by defaultMasterKey with zeroize-on-drop, never written to disk

Installation

Add this to your Cargo.toml:

[dependencies]
encryptman-keyring = "0.1"

Quick Start

use encryptman_keyring::Vault;

// First call: generates key → stores in OS keychain
// Later calls: loads existing key from keychain
let vault = Vault::new("my-app").unwrap();

let encrypted = vault.encrypt("my_database_password").unwrap();
let decrypted = vault.decrypt(&encrypted).unwrap();

assert_eq!(decrypted, "my_database_password");

// Delete the key from the keychain when no longer needed
Vault::delete("my-app").unwrap();

Usage

Binary data

use encryptman_keyring::Vault;

let vault = Vault::new("my-app").unwrap();

let data = b"binary secret data";
let encrypted = vault.encrypt_bytes(data).unwrap();
let decrypted = vault.decrypt_bytes(&encrypted).unwrap();

assert_eq!(decrypted, data);

Multiple contexts with one vault

use encryptman_keyring::Vault;

let vault = Vault::new("my-app").unwrap();

let db_secret = vault.encrypt_with_context("database", "postgres://...").unwrap();
let api_secret = vault.encrypt_with_context("api-keys", "sk-12345").unwrap();

// Same plaintext, different contexts → different ciphertext
assert_ne!(db_secret, api_secret);

// Decrypt with the matching context
let db_plain = vault.decrypt_with_context("database", &db_secret).unwrap();

Custom target (username)

use encryptman_keyring::Vault;

// Store separate keys for different users / environments
let dev_vault = Vault::new_with_target("my-app", "development").unwrap();
let prod_vault = Vault::new_with_target("my-app", "production").unwrap();

Migrating from file-based keys

use encryptman_keyring::Vault;

// Reads .key → stores in keychain → deletes the file
let vault = Vault::migrate_from_file("my-app", std::path::Path::new("/path/to/.key")).unwrap();

How It Works

Vault::new("my-app")
    │
    ├── keyring::Entry::new("my-app", "master-key")
    │       │
    │       ├── get_secret() → OK → MasterKey::from_bytes()
    │       └── get_secret() → NoEntry → MasterKey::generate() → set_secret()
    │
    └── encryptman::encrypt / decrypt using the master key
  • Key Storage: Master key (32 bytes) stored in the OS native credential store.
  • Key Derivation: encryptman uses HKDF-SHA256 with "encryptman:{service}" as context.
  • Encryption: AES-256-GCM with random 12-byte nonces.

Platform Notes

Platform Credential Store Notes
Windows Credential Manager Requires Windows Vista or later
macOS Keychain May prompt for keychain unlock on first access
Linux Secret Service (DBus) Requires a Secret Service provider (GNOME Keyring, KeePassXC)

When NOT to use this crate

  • Headless / CI environments — the OS keychain may not be available.
  • Multi-user servers — keyring entries are per-user; consider a shared secret store like Vault or AWS Secrets Manager.

Minimum Supported Rust Version

MSRV: 1.85 (edition 2024)

License

Licensed under either of:

at your option.