Security model

What we cannot see, we cannot lose.

Rempar is designed so that a full server compromise reveals no secret. Here is how, without detours.

Key derivation

The master password is normalized (NFKC) then derived with Argon2id. Two sub-keys come out through HKDF: one to authenticate, one to wrap the vault key. Neither can ever recover the other.

master_key = Argon2id(password, salt, m=65536 KiB, t=3, p=4)
auth_key   = HKDF(master_key, "rempart/auth/v1")
wrap_key   = HKDF(master_key, "rempart/wrap/v1")

Per-item key

Each item has a random 32-byte key sealed by the vault key. Content is encrypted with XChaCha20-Poly1305 and the item id is bound into the authenticated data.

blob = { k: seal(vault_key, item_key), c: seal(item_key, content) }

Zero knowledge

The server stores the hash of auth_key, the public KDF parameters and opaque blobs. It knows no password, no key, no item name. Pre-login returns a deterministic fake salt for unknown e-mails: no account enumeration.

Account and devices

Per-device access token, rotating refresh token. A replayed token revokes the device. TOTP 2FA (Google Authenticator) protects login. You revoke a lost device from any other.

Recovery kit

32 random bytes shown once in Crockford base32. A copy of the vault key is sealed with it. Without master password and without kit, nothing is recoverable, by anyone.

Security gestures

Secrets hidden by default, re-hidden after 30 s. Clipboard cleared after 30 s. Lock after 5 min, on sleep and on close, with the key wiped from memory. Progressive delays after failures: 30 s, 1 min, 5 min. No silent wipe.

What the server never sees

    • Your master password
    • The master key, the wrap key and the vault key
    • The content or name of any item
    • Your recovery kit
    • More than 5 hash characters during a breach check