Files
hacks/bip85ssh/README.md
clawbot d3daa14d54 bip85ssh: add spec for deterministic SSH keys from BIP-85
README for a new tool that derives ed25519 SSH key pairs from a BIP-39
mnemonic or xprv, using pkg/bip85 from sneak/secret with the same steps
as agehd. Path m/83696968'/592366788'/1822331379'/n'. Four commands:
pub, priv, install, ssh. The README is the spec; the code follows in
later commits.

Model: fable-5-1
2026-09-06 14:19:32 +00:00

3.8 KiB

bip85ssh

bip85ssh turns a BIP-39 mnemonic (or a BIP-32 xprv) into SSH key pairs that can be recreated from that secret at any time. The same secret and the same index always give the same key. Only ed25519 keys are produced.

It uses the BIP-85 entropy deriver from git.eeqj.de/sneak/secret/pkg/bip85 and follows the same steps as that repository's agehd package.

Derivation

The secret is turned into a key like this:

  1. mnemonic -> BIP-39 seed (empty passphrase), or the xprv is parsed directly;
  2. seed -> BIP-32 master key;
  3. master key -> 64 bytes of BIP-85 entropy at the path below;
  4. entropy -> BIP-85 DRNG (SHAKE256); read 32 bytes;
  5. those 32 bytes are the ed25519 seed.

The path is:

m/83696968'/592366788'/1822331379'/<n>'
  • 83696968 is the fixed BIP-85 purpose.
  • 592366788 is the vendor id, sha256("berlin.sneak") & 0x7fffffff, the same one agehd uses.
  • 1822331379 is the application id, sha256("bip85ssh") & 0x7fffffff.
  • n is the key index: flag --index / -n, default 0.

Test vector, mnemonic abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about:

index 0: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1esgfi4OeaywgKh0o5r/8lMOUlUD/N+YoAiC8SNEML
index 1: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB26T7hdDuUF6wfTQ7NpIpyeTgGha4NlhQjaAhap5dqs

Giving it the secret

The secret is never taken as a command-line argument. It is looked for in this order; the first one found wins:

  1. --mnemonic-file <path> or --xprv-file <path>: the file holds the secret on one line.
  2. Environment variable BIP85SSH_MNEMONIC or BIP85SSH_XPRV.
  3. A prompt on the terminal with echo turned off. The prompt accepts either a mnemonic or an xprv; a value starting with xprv is treated as an xprv.

If none of these is available and standard input is not a terminal, the tool refuses and exits with status 1.

Commands

Every command takes --index / -n and the secret flags above, and has --help. bip85ssh --version prints the version set at build time.

bip85ssh pub

Prints one authorized_keys line to standard output:

ssh-ed25519 <key> <comment>

The comment defaults to bip85ssh/<n>; change it with --comment.

bip85ssh priv

Prints the unencrypted private key in OpenSSH format (the -----BEGIN OPENSSH PRIVATE KEY----- block that ssh reads) to standard output and nothing else, so it can be redirected into a file. The key's comment is the same as for pub.

bip85ssh install <[user@]host> [-- ssh options...]

Runs the system ssh to the host and, on the host:

  • creates ~/.ssh with mode 0700 if it is missing;
  • creates ~/.ssh/authorized_keys with mode 0600 if it is missing;
  • appends the pub line only if an identical line is not already there.

It then prints added or already present. How this ssh connection authenticates is up to the user's normal ssh setup (existing keys, agent, password). Anything after -- is passed to ssh unchanged.

bip85ssh ssh <host> [ssh arguments...]

Derives the key, serves it from an SSH agent that runs inside the tool on a unix socket in a new private 0700 temporary directory, then runs the system ssh with -o IdentityAgent=<that socket> followed by the host and all remaining arguments unchanged. The tool exits with ssh's exit status and removes the socket and directory on the way out. The private key is never written to disk.

Errors

Errors go to standard error and the exit status is 1, except for the ssh command, which passes through ssh's own exit status.

Building and running

make build    # produces ./bip85ssh
make check    # fmt-check, lint (golangci-lint) and tests

Examples:

bip85ssh pub -n 3
bip85ssh priv > ~/.ssh/id_bip85_3
bip85ssh install -n 3 user@example.com
bip85ssh ssh -n 3 user@example.com uptime