Skip to main content

detssh

Deterministic Ed25519 SSH key generation from a seed passphrase. Same passphrase + same parameters → same keypair, every time, on any machine - nothing to back up but what's in your head.

detssh

Prompts for everything (passphrase hidden + confirmed) and writes to the same place ssh-keygen would: ~/.ssh/id_ed25519 / ~/.ssh/id_ed25519.pub (mode 600/700, ~/.ssh created if missing). Pass --output to write somewhere else instead.

Non-interactively:

detssh --kdf argon2id --salt-algo blake2b --seed "..." --label github --overwrite-files

Any flag switches to non-interactive mode: missing optional fields fall back to their defaults, --seed is the only required one. Passing --seed on the command line puts it in your shell history and process list (ps aux) - fine for local scripting, but prefer the interactive prompt when that matters.

By default the private key file is written unencrypted, like ssh-keygen -N "". Pass --key-passphrase (or leave it blank at the interactive prompt to skip) to encrypt it at rest instead - anyone who gets the file will still need that passphrase to use it. This is unrelated to the seed passphrase: it never touches key derivation, so it doesn't need to be remembered to recreate the key, only to unlock the file you already have. Same caveat as --seed applies if passed as a flag.

Using the key with ssh

ssh only auto-offers keys with default filenames (id_rsa, id_ed25519, ...) sitting directly in ~/.ssh/ - a key written under --output or a per-label subdirectory needs either -i <path>, a hand-written Host block in ~/.ssh/config, or ssh-adding it to your agent.

The interactive run offers to do this for you at the end, right after it writes the key:

Register this key so `ssh isik:personal:contabo` connects with it? [Y/n]: y
Destination (user@host): root@contabo.com
Non-default ssh port:

Registered isik:personal:contabo -> root@contabo.com
Run: ssh isik:personal:contabo

The label you derived the key with doubles as the Host name, so there's nothing extra to type. In flag mode, --register root@contabo.com (plus --register-port when it isn't 22) does the same thing, and needs --label for that reason. Declining changes nothing about the key that was written.

For a key you already have, detssh ssh register reaches the same end state:

detssh ssh register isik:personal:contabo root@contabo.com --key ~/.ssh/isik:personal:contabo/id_ed25519

Either route records the label in ~/.config/detssh/config, generates a Host block for it in a detssh-managed file, and adds a single Include line to ~/.ssh/config (once, at the top) that pulls it in. After that, ssh isik:personal:contabo just works - through real ssh, nothing routed through detssh at connect time.

detssh ssh list              # show registered labels
detssh ssh forget <label>    # remove a label (never deletes the key file)

Backends

  • --kdf: argon2id (default), argon2i, argon2d, scrypt, pbkdf2, bcrypt_pbkdf
  • --salt-algo: blake2b (default), blake2s, sha256, sha384, sha512, sha3_256, sha3_384, sha3_512

Each combination has its own options (cost knobs, salt digest size, etc.), with their valid ranges shown in both --help and the interactive prompts. See them with:

detssh --kdf <kdf> --salt-algo <salt-algo> --help

We recommend sticking with the defaults (argon2id, memory-hard with a high cost) unless you have a specific reason not to - they make brute-forcing your passphrase significantly more expensive than faster KDFs like pbkdf2.

Cost knobs (iterations, memory, cost, rounds, ...) also carry a soft safety limit meant to catch typos before they cost you minutes of derivation time. In interactive mode, going over one doesn't interrupt you - everything you exceeded is summarized in one confirmation at the very end. In flag mode, it fails immediately unless you pass --force-allow-soft-constraints.

Determinism guarantee

Same explicit parameters → same key, across any release sharing the same major version - only a major version bump may change key derivation. That guarantee starts at 1.0; we're still on 0.x, so it doesn't apply yet (see tests/golden/README.md).

Development

uv sync
uv run pytest
uv run ruff check .

pytest runs with coverage on by default ([tool.pytest.ini_options] in pyproject.toml) and fails under 100% line+branch coverage - same gate locally and in CI, nothing extra to remember to pass.

Metadata

Release files for detssh 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for detssh 0.4.0
File Size Uploaded Provenance
detssh-0.4.0.tar.gz 89.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for detssh 0.4.0
File Interpreter ABI Platform
detssh-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 113.4 kB

Release files / detssh-0.4.0.tar.gz

Download URL detssh-0.4.0.tar.gz
Size 89.1 kB
Tags Source
SHA-256 checksum
How to use checksums
84f519cde657fc32f1e5a74c573bf29d8edcd0f30e9580594092be4847cb6625
BLAKE2b-256 checksum
How to use checksums
ce9b3bc9a5b91b6bb2f76531c78d66caab72e45844c8aad4bd99ad007dd323bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / detssh-0.4.0-py3-none-any.whl

Download URL detssh-0.4.0-py3-none-any.whl
Size 24.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2325f3cf067cb7e946201de18c89bd1a074334e63750a68c4b3979add9bcdd32
BLAKE2b-256 checksum
How to use checksums
5939b57dfe4d3db6e97c087de22ff74a286600b9771b70839e71230069f2ee04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Security for detssh 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for detssh-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page