Securely share a password or note
Send a secret without trusting any single party — including our server. The message is encrypted in your browser, and the key is split so that no one piece can decrypt anything on its own.
Compose
Share
What the recipient sees
PreviewWhen the recipient opens https://youshallnotpass.io/decrypt/… , they enter the passphrase you sent through other channels and decrypt the secret locally in their browser.
How it works
Passphrase generation. Your browser generates each passphrase as 52 random Crockford base32 characters (crypto.getRandomValues, 256 bits of entropy per passphrase). The passphrase string itself is the secret — there's no separate "encoded key" hiding behind it, and no characters that don't matter.
Key derivation. Each passphrase is hashed with SHA-256 into a 32-byte share. Those passphrase shares are XOR-combined with one extra random server share to produce the AES-256-GCM key. Because every character feeds the hash, changing a single character anywhere in any passphrase yields a completely different key — and AES-GCM's auth tag rejects it.
Encryption. Your browser encrypts the secret with that key using AES-256-GCM, with a random per- message IV and the built-in auth tag for tamper detection. The plaintext and the full key never leave your device.
What the server stores. A single row: the ciphertext, the IV, the server share, the expiration, a max view count, and a current view counter. The server has no way to derive the AES key from this — it would need the passphrases too, and those only exist in the sender's and the recipient's heads (and your clipboard, briefly).
Channel separation. Send the link through your normal channel (Slack, email) and each passphrase through a different one (SMS, in person). An attacker would have to compromise every channel at once to read the secret.
Lifecycle. Each record has an expiry and a maximum number of decrypt tries. Every Decrypt click makes a fresh server roundtrip — the recipient's browser never caches the ciphertext, IV, or server share between attempts — and the server atomically increments the counter in the same transaction. When the counter hits the limit (or the record expires), the row is deleted in the same transaction. No recovery after deletion.