Master key
Argon2id over your password and a per-account salt, run entirely on your device. Held in memory for the session, never written to disk or sent anywhere.
Zero-knowledge is a tested property of the architecture, not a claim painted on after the fact.
Master passwords and vault plaintext stay on clients. The AU API stores opaque encrypted blobs, sync metadata, and organisation membership — enough to move ciphertext between devices, not enough to open a vault.
Server assemblies are forbidden from referencing the client crypto library or decrypting AES-GCM payloads. That boundary is enforced by dedicated zero-knowledge tests.
A master password becomes four purpose-built keys, each with one job. Only one of them ever leaves your device — and that one can't unlock anything.
Argon2id over your password and a per-account salt, run entirely on your device. Held in memory for the session, never written to disk or sent anywhere.
An HKDF branch of the master key whose only job is unwrapping your vault key. Domain-separated so it can never be reused for anything else.
32 random bytes generated once at signup, never re-derived. It's what your vault is actually encrypted under, so changing your password just re-wraps this key — your vault itself is never touched.
The only password-derived value that leaves your device — and it can't unwrap anything. The server peppers and re-hashes it before storage, so a stolen database dump still can't be brute-forced offline.
Every encrypted value — a vault item, a wrapped key, an attachment chunk — uses the same small binary envelope, so there's one code path to audit for how ciphertext is built and read back.
AES-256-GCM: [0x01 version][0x01 alg][12-byte nonce][ciphertext ‖ 16-byte tag]
RSA-OAEP wrap: [0x01 version][0x02 alg][384-byte RSA-3072-OAEP-SHA256 ciphertext]
AES-GCM isn't key-committing, so a failed decrypt is usually — not certifiably — attributable to the wrong password rather than tampering. We only lean on that inference where it's low-stakes (telling a user their password is wrong); every other envelope treats a decrypt failure as an integrity error, full stop.
Organisations need shared vault access. The naive way — the server hands out a shared key — makes the server a party to your secrets. PassStash wraps it per-recipient instead.
An admin wraps the organisation's shared key under one member's RSA-OAEP public key at a time — never a key the server could unwrap on its own.
The admin signs the wrap (RSA-PSS) over the org, member, member's public key, and key version. The server stores every public key in plaintext — without this signature, a compromised server could substitute its own key into the wrap. With it, a member only accepts a wrap that verifies against a pinned signer.
Zero-knowledge cuts both ways: lose your master password with no recovery set up, and that vault is gone — nobody, including us, holds a spare key. Organisations can opt into a recovery path that keeps that guarantee intact for everyone who doesn't use it.
Argon2id key derivation and AES-GCM envelopes are implemented in both C# and TypeScript against shared vector suites.
TLS terminates on Ripple’s shared ingress. PassStash customer names stay DNS-only on Cloudflare so client IPs remain visible for rate limits.
TOTP 2FA, JWT rotation / JWKS, and HIBP breach checks are implemented. Encrypted export/import and pepper-rotation runbooks continue to land.
| Data | Server visibility |
|---|---|
| Vault item contents | Never — ciphertext only |
| Your master password | Never transmitted in any form |
| Keys that could decrypt your vault | Never — no such key exists server-side |
| Full password-breach hash | Never — only a 5-character prefix |
| Peppered, hashed authentication value | Yes — used only to verify login |
| Sync metadata (timestamps, item IDs, key versions) | Yes — required to sync ciphertext between devices |
| Account info (email, organisation membership) | Yes — needed to run the account and org system |
A compromised client device can still expose unlocked vault material. PassStash’s promise is that a breached sync region cannot decrypt customer vaults from stored data alone.