Technical Overview
Security Architecture
keyhold.io uses a zero-knowledge architecture. We've designed the system so that we mathematically cannot decrypt your secrets — not "we promise not to", but we literally can't.
Cryptographic Primitives
All client-side cryptography uses the Web Crypto API. We use industry-standard algorithms with conservative parameters.
| Purpose | Algorithm | Parameters |
|---|---|---|
| Secret encryption | AES-256-GCM | 256-bit key, 96-bit IV |
| Key wrapping | RSA-OAEP | 2048-bit, SHA-256 |
| Key derivation | PBKDF2 | SHA-256, 100,000 iterations |
| Server-side key protection | AWS KMS | Hardware-backed, AES-256-GCM |
Split-Key Architecture
Every secret is encrypted with an ephemeral AES key that is immediately split into two shares. Neither share is useful on its own.
Client Share
Encrypted with RSA and stored in our database. Can only be decrypted by authorised users who hold the corresponding private key.
Server Share
Encrypted with AWS KMS and stored in our database. We can decrypt this share, but it's useless without the client share.
The key insight
The two shares are combined using XOR to reconstruct the original encryption key. Given only the server share, the original key is computationally indistinguishable from random noise. We hold one share; you hold the other. Neither works alone.
Key Hierarchy
User Keys
Each user has an RSA keypair generated during account setup. The public key is stored in plaintext. The private key is encrypted using a key derived from the user's password (via PBKDF2) and stored encrypted. We never see your password or your private key.
Client Keys
Each client (project) has its own RSA keypair. The private key is encrypted separately for each authorised team member using their public key. This allows access to be granted or revoked per-user without re-encrypting secrets.
Secret Keys
Each secret gets a fresh random AES-256 key. This key encrypts the secret data, then is immediately split and discarded. The encrypted secret and the two encrypted shares are stored; the original key never persists anywhere.
Encryption & Decryption
When a secret is submitted
All encryption happens in the submitter's browser before any data leaves their device. The browser generates a random key, encrypts the secret with AES-256-GCM, splits the key into two shares, encrypts each share separately, and only then transmits the encrypted components to our servers.
We receive ciphertext. We never see plaintext.
When a secret is revealed
The server verifies authorisation, decrypts the server share via KMS, and returns both encrypted shares plus the ciphertext. The user's browser decrypts the client share using their private key, XORs the two shares to recover the original AES key, and decrypts the secret locally.
Decryption happens entirely in your browser.
AWS KMS
The server share is protected by AWS Key Management Service, which provides hardware-backed key storage and comprehensive audit logging.
Encryption context — Each encrypted share is bound to a specific organisation. Attempting to decrypt with a mismatched context fails.
IAM policies — Strict permissions limit which services can perform encrypt/decrypt operations.
CloudTrail — Every KMS operation is logged for audit and compliance purposes.
Device Trust
Users can optionally "remember" a device for faster access. When enabled, a session key is derived from the user's password using PBKDF2 and stored encrypted in the browser's localStorage.
This allows the browser to unlock the user's private key without re-entering their password each time, but only on that specific device and only with the correct password. The session key never leaves the browser and is scoped to the individual user.
Security Properties
Zero-knowledge
We never see plaintext secrets. All encryption and decryption happens client-side. Our servers store only ciphertext and encrypted key shares.
Server compromise resistance
If our database is breached, attackers obtain encrypted blobs. Without users' private keys — which never leave their browsers — decryption is computationally infeasible.
Forward secrecy
Each secret uses a fresh ephemeral key. Compromising one secret's key material has no effect on any other secret.
Authenticated encryption
AES-256-GCM provides both confidentiality and integrity. Any tampering with ciphertext is detected during decryption.