Keygrain derives passwords on demand from your master secret using key-stretching and HMAC. Nothing is stored. Nothing can be breached. The same inputs always produce the same output.
Every password is computed fresh from three inputs: your secret, your email, and the site name. The derivation pipeline uses two cryptographic primitives — Argon2id for key strengthening and HMAC-SHA256 for deterministic derivation.
The result: a deterministic, high-entropy password that meets site requirements and is reproducible from the same inputs on any platform.
If you use optional encrypted sync, here is the exact trust boundary between your device and the Keygrain server:
All cryptographic operations happen on your device. The server receives only AES-256-GCM ciphertext encrypted with a key derived from your secret — a key the server never sees. Even a complete server compromise yields nothing but opaque blobs.
| Property | Implementation | Purpose |
|---|---|---|
| Key strengthening | Argon2id (RFC 9106) — 64 MiB memory, 3 iterations, parallelism 1 | ~1 second per guess on a single CPU core. Memory-hardness increases cost on GPUs/ASICs, but does not eliminate the advantage of high-bandwidth-memory hardware. |
| Per-user salt | "keygrain-strengthen:" + email |
Prevents multi-target amortization. Each user requires independent attack effort. |
| Password derivation | HMAC-SHA256 keyed by strengthened key | Knowing one derived password does not reveal the strengthened key or other passwords. |
| Domain separation | Unique message suffixes per derivation type | Password, auth, encryption, TOTP, SSH, and wallet derivations are cryptographically independent. |
| Unbiased selection | Rejection sampling (discard bytes ≥ floor(256/n)*n) | No modular bias in character selection. Every position is uniformly distributed. |
| Sync encryption | AES-256-GCM — 32-byte key, 12-byte random nonce, 16-byte auth tag | Authenticated encryption. Server cannot read or tamper with service data. |
| Auth to server | Derived 32-character password, bcrypt cost-12 server-side | Server stores only a hash. Compromised server cannot authenticate as the user elsewhere. |
| Determinism | Same inputs → identical output, cross-platform | No sync required for basic use. Any correct implementation reproduces the same passwords. |
If your secret is exposed — through phishing, a keylogger, or shoulder surfing — all your passwords are compromised simultaneously. This is the fundamental trade-off of deterministic derivation: one secret protects everything. Use Keygrain only on trusted devices, and choose a high-entropy secret (6+ random words recommended).
Argon2id costs ~1 second per guess. A 4-digit PIN has 10,000 candidates — exhaustible in ~3 hours. A short dictionary word falls similarly fast. The strengthening buys time, not invulnerability. Your security is bounded by your secret's entropy.
Keygrain does not check whether derived passwords have appeared in data breaches. If a site is compromised and stores your password in plaintext, you must manually rotate by incrementing the counter for that site.
If malware has access to your device's memory or keyboard input, it can capture your secret as you type. No software can protect against a hostile operating environment. Keygrain assumes your device is trustworthy.
The 4-color fingerprint has only 4,096 possible combinations (8⁴). It catches typos — it does not authenticate you. An attacker who observes your fingerprint pattern can confirm a guessed secret or narrow the search space.
A malicious sync server could serve stale encrypted payloads, reverting your configuration to an older state. It cannot forge new content (it lacks the encryption key), but it can replay valid old ciphertext. ETag-based locking mitigates unintentional replays.
Keygrain's algorithm is fully specified with test vectors. You can verify that any implementation produces correct output by running the reference tests:
git clone https://dev.secbytech.com/opensource/keygrain
cd keygrain/python
pip install -e .
python -m pytest tests/
The repository root contains vectors.json with machine-readable test vectors. Every implementation (Python, JavaScript, Kotlin) must produce byte-identical output. The full algorithm specification is MIT-licensed — there is no secret sauce, only well-understood cryptographic primitives composed carefully.
Last reviewed: June 2026