Project

ssh-tresor

0.0
The project is in a healthy, maintained state
Independent Ruby implementation of ssh-tresor using ssh-agent signatures, HKDF-SHA256, and AES-256-GCM.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 13.3
~> 3.13
~> 0.9

Runtime

~> 0.3
 Project Readme

ssh-tresor-ruby

ssh-tresor encrypts and decrypts secrets using keys available through ssh-agent.

The private key never leaves the SSH agent. Encryption creates a random master key, asks the agent to sign random per-key challenges, derives slot keys with HKDF-SHA256, and stores an AES-256-GCM encrypted master key slot for each SSH key. Decryption works when one matching SSH key is loaded locally or forwarded with ssh -A.

It is freely inspired by the ssh-tresor project but doesn't depend on it.

Usage

gem install ssh-tresor
ssh-tresor list-keys
echo -n "secret" | ssh-tresor encrypt -a > secret.tresor
ssh-tresor decrypt secret.tresor
ssh-tresor list-slots secret.tresor
ssh-tresor add-key -k SHA256:abc < secret.tresor > updated.tresor
ssh-tresor remove-key -k SHA256:abc < updated.tresor > reduced.tresor

Library API

bundle add ssh-tresor

Your application or other gems can depend on ssh-tresor-ruby and call it directly:

require "ssh_tresor"

vault = SshTresor::Vault.new

encrypted = vault.encrypt("secret", armor: true)
plaintext = vault.decrypt(encrypted)

updated = vault.add_key(encrypted, fingerprint: "SHA256:abc", armor: true)
slots = vault.list_slots(updated)
keys = vault.list_keys

The Vault instance connects to SSH_AUTH_SOCK by default. You can inject a custom agent object for tests or alternate transports:

vault = SshTresor::Vault.new(agent: my_agent)

The lower-level SshTresor::TresorBlob parser and SshTresor::Tresor module remain available if you need direct access to parsed slots.

Wire Format

The implementation writes and reads the SSHTRESR v3 format:

Header:  SSHTRESR (8) + version (1) + slot_count (1)
Slot:    fingerprint (32) + challenge (32) + nonce (12) + encrypted_key (48)
Data:    nonce (12) + ciphertext including 16-byte AES-GCM auth tag