Convert SSH Ed25519 keys to age keys. This is useful for usage in sops-nix and sops
- Exports the private key:
$ ssh-to-age -private-key -i $HOME/.ssh/id_ed25519 -o key.txt
$ cat key.txt
AGE-SECRET-KEY-1K3VN4N03PTHJWSJSCCMQCN33RY5FSKQPJ4KRRTG3JMQUYE0TUSEQEDH6V8If your private key is encrypted, pipe the passphrase via -stdinpass:
$ systemd-ask-password | ssh-to-age -private-key -stdinpass -i $HOME/.ssh/id_ed25519 -o key.txt
$ security find-generic-password -w -s 'SSH Key Passphrase' | ssh-to-age -private-key -stdinpass -i $HOME/.ssh/id_ed25519 -o key.txtAlternatively, pass it via SSH_TO_AGE_PASSPHRASE environment variable.
- Exports the public key:
$ ssh-to-age -i $HOME/.ssh/id_ed25519.pub -o pub-key.txt
$ cat pub-key.txt
age17044m9wgakla6pzftf4srtl3h5mcsr85jysgt5fg23zpnta8sfdqhzn452ssh-to-age also supports multiple public keys at once seperated by newlines and ignores unless ssh keys that are not in the ed25519 format. This makes it suiteable in combination with ssh-keyscan:
$ ssh-keyscan eve.thalheim.io eva.thalheim.io | ssh-to-age
# eve.thalheim.io:22 SSH-2.0-OpenSSH_8.6
...
age1hjm3aujg9e79f5yth8a2cejzdjg5n9vnu96l05p70uvfpeltnpms7yy3pp
age1v8zjc47jmlqwefyu66s0d4ke98qr4vnuj3cpvs4z9npfdw833dxqwjrhzvssh-to-age deterministically derives an X25519 (age) key from an Ed25519 SSH
key using the standard Ed25519-to-X25519 birational map (see
Filippo Valsorda's write-up):
- The age private scalar is
sha512(seed)[:32]— the same scalar Ed25519 itself derives from the seed per RFC 8032. No new key material is generated. - The age public key is the Montgomery form of the Ed25519 public point.
- The mapping is deterministic in one direction only. You cannot recover the original SSH private key from an age key: SHA-512 is one-way, and the OpenSSH key file (seed, nonce-generation half of the hash, optional passphrase-based encryption) cannot be reconstructed from the X25519 scalar.
- The age key does not grant SSH authentication — Ed25519 signing also requires the raw seed, which is not recoverable from the age key.
A common pattern is using a passphrase-protected SSH key together with an
unencrypted age key for sops / sops-nix. Be aware that:
- An attacker with read access to the age key file can decrypt every secret encrypted to the derived age public key. This bypasses the passphrase protection of the SSH key for decryption purposes.
- SSH authentication itself remains protected by the passphrase.
If you want the age key to inherit the at-rest protection of your SSH key,
do not derive it from that SSH key. Generate a dedicated age identity and
protect it separately — for example with
age-plugin-yubikey,
age-plugin-tpm, or by keeping
it on an encrypted volume that is unlocked on demand.
$ nix-shell -p 'import (fetchTarball "https://github.com/Mic92/ssh-to-age/archive/main.tar.gz") {}'$ go install github.com/Mic92/ssh-to-age/cmd/ssh-to-age@latest