Keygrain
Deterministic password, SSH key, and wallet derivation from a master secret.
Install
pip install keygrain
CLI Usage
export KEYGRAIN_SECRET="your-master-secret"
keygrain me@example.com --site github.com
keygrain ssh me@example.com --name github
keygrain wallet me@example.com --name savings --chain bitcoin
Sync + Local Cache (read-only)
The CLI can download your synced services from the Keygrain server and store them in a local encrypted cache, then retrieve passwords / TOTP codes / SSH keys offline. The CLI is read-only: it never writes to the server. Add or change services with the browser extension or the Android app.
# Download and cache your account's services (the only networked command):
keygrain sync --email me@example.com
# List cached services (offline; no network):
keygrain list
keygrain list --type totp
keygrain list --site github.com
# Retrieve one credential (offline; no network):
keygrain get --site github.com # password (default)
keygrain get --site github.com --totp # current TOTP code
keygrain get --site github.com --ssh # authorized_keys line
keygrain get --site github.com --ssh --private # OpenSSH private key
keygrain get --id 550e8400-e29b-41d4-a716-446655440000 # select by exact id
# Seal a machine into offline-only mode (and lift it):
keygrain sync --lock
keygrain sync --unlock
# Self-hosted server:
keygrain sync --server https://sync.example.com
Site matching is a whole-label suffix match (github.com matches
accounts.github.com but bank does not match fakebank.com). Any ambiguous
match is a hard error listing the candidates — the CLI never guesses. The
resolved (site, service-email) is always echoed to stderr before a secret is
printed to stdout.
The cache lives at ~/.keygrain/accounts/<slug>.kg (AES-256-GCM, 0600). The
master secret is never written to disk.
What a compromised sync server can (and cannot) do
The sync server only ever stores an encrypted blob plus a small unauthenticated
metadata array (id + updated_at per service); it never sees your master secret
or any derived credential. A hostile or compromised server therefore cannot
exfiltrate secrets, decrypt your services, or leak data across accounts — the blob
is AES-256-GCM encrypted under a key derived from your secret, and the CLI verifies
its checksum and GCM tag before use.
The one thing a hostile server can influence is that unauthenticated metadata: by
tampering with the id values it could, at most, cause get --id <uuid> to resolve
to a different service that is still your own — it cannot inject a foreign or
attacker-controlled entry. The mandatory stderr echo of the resolved
(site, service-email) before any secret is printed is the guard: always read that
line to confirm you got the credential you intended. (The CLI also drops any
metadata id that is not UUID-shaped and strips control characters, so tampered
ids cannot inject terminal escape sequences.)
Providing the master secret
sync, list, and get accept the master secret from exactly one of:
# Interactive hidden prompt (default when run in a terminal):
keygrain get --site github.com
# Environment variable — for CI/CD with injected secrets:
keygrain get --site github.com --secret-env KEYGRAIN_SECRET
# File — for Docker/Kubernetes secrets mounted as files:
keygrain get --site github.com --secret-file /run/secrets/keygrain_secret
A raw --secret VALUE argument is intentionally not provided (it would leak
via ps / shell history). The CLI does not auto-load .env files.
Library Usage
from keygrain import derive_password, normalize_site
password = derive_password(
secret=b"my-secret",
email="me@example.com",
site=normalize_site("github.com"),
)
Features
- Argon2id key strengthening (64 MiB, 3 iterations)
- HMAC-SHA256 derivation — single password compromise reveals nothing
- TOTP seed derivation
- SSH Ed25519 key derivation
- BIP-39 wallet mnemonic derivation
- BIP-85 child mnemonic derivation
- Cross-platform compatible (Python, Kotlin, JavaScript)
Documentation
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keygrain-1.0.0.tar.gz.
File metadata
- Download URL: keygrain-1.0.0.tar.gz
- Upload date:
- Size: 65.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af1a3ddb55f06eaf8f65b5ac8147476bf7deb55374c3631522ec7027bafff33b
|
|
| MD5 |
e3b15ea5339f5e9490599b9873d9d943
|
|
| BLAKE2b-256 |
8e9770ff5e5b066dba7dd6ad33f92f14c726018c24acc5706cf2f3fba62e7abc
|
Provenance
The following attestation bundles were made for keygrain-1.0.0.tar.gz:
Publisher:
publish.yml on iheb-eddine/keygrain
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keygrain-1.0.0.tar.gz -
Subject digest:
af1a3ddb55f06eaf8f65b5ac8147476bf7deb55374c3631522ec7027bafff33b - Sigstore transparency entry: 2231860891
- Sigstore integration time:
-
Permalink:
iheb-eddine/keygrain@9f72d7d7972b4da951ee5e655a4a48c0fa22f91f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/iheb-eddine
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f72d7d7972b4da951ee5e655a4a48c0fa22f91f -
Trigger Event:
release
-
Statement type:
File details
Details for the file keygrain-1.0.0-py3-none-any.whl.
File metadata
- Download URL: keygrain-1.0.0-py3-none-any.whl
- Upload date:
- Size: 41.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7199eee20e2afb08c49affcbcda6b3ac09b6cfa49659df393d0af06f40964f55
|
|
| MD5 |
1c1cde74454a564e51d54a6030d68c41
|
|
| BLAKE2b-256 |
5b637d816e1cd39747727e1615883952ac5867118ebc82378b587d32eaa60986
|
Provenance
The following attestation bundles were made for keygrain-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on iheb-eddine/keygrain
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
keygrain-1.0.0-py3-none-any.whl -
Subject digest:
7199eee20e2afb08c49affcbcda6b3ac09b6cfa49659df393d0af06f40964f55 - Sigstore transparency entry: 2231861023
- Sigstore integration time:
-
Permalink:
iheb-eddine/keygrain@9f72d7d7972b4da951ee5e655a4a48c0fa22f91f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/iheb-eddine
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f72d7d7972b4da951ee5e655a4a48c0fa22f91f -
Trigger Event:
release
-
Statement type: