Secrets::Vault
Vault encryption / decryption via shell-out to the age(1) binary
(https://age-encryption.org).
v0.1 supports single-recipient only. Both encrypt and decrypt are
streaming via stdin/stdout — the plaintext is never written to a
disk file. The identity (private key) is briefly written to a
mode-0600 temp file because age -i requires a path; the file is
deleted as soon as age returns.
Instance methods
Decrypt ciphertext (ASCII-armored age PEM) using identity
(an "AGE-SECRET-KEY-1..." private key string). Returns the
plaintext as a String.
Decrypt a passphrase-encrypted recovery paper blob.
Encrypt plaintext to ASCII-armored age PEM for recipient
(a public key string starting with "age1...").
Single-recipient overload retained for backward compatibility with the v0.1–v0.3 API. New code should prefer the array form.
Encrypt plaintext to ASCII-armored age PEM for the given list
of recipient public keys. Each key must start with "age1...".
age(1) natively supports multi-recipient encryption: any of
the corresponding identities can later decrypt the file.
Empty list raises VaultError — encrypting to nobody is never
what the caller intended.
Encrypt with a passphrase (used for the recovery paper export).
age -p prompts via /dev/tty; we feed the passphrase on a
second pipe via the AGE_PASSPHRASE env var when available, or
via a tty wrapper. Simplest robust path: shell-out to age -p
with the passphrase fed twice on stdin (age prompts then asks
for confirmation when encrypting).
Encrypt with a passphrase (used for the recovery paper export).
Why not age -p? Because age -p insists on reading the
passphrase from /dev/tty, which can't be fed without spawning
a pseudo-terminal. For the paper recovery use case we use
openssl enc with PBKDF2 (600 000 iterations, SHA-256,
AES-256-CBC), which accepts the passphrase via
-pass pass:STRING directly. openssl is available on every
Unix-like system (LibreSSL on macOS, OpenSSL on Linux/FreeBSD).
The output is base64-armored and wrapped in PEM-like markers so the paper format is clearly identifiable.
Where to put the brief identity tempfile. macOS doesn't expose a tmpfs by default; /tmp is fine for a sub-100ms exposure.