← back to the app

Technology

How friend-lock works

A file you lock for a friend so that only they can open it — and you can't reopen it yourself. Here's exactly what happens under the hood, and why it's safe to share the "lock code".

The core idea: public-key cryptography

The tempting first design is: my friend hashes their password, gives me the hash, I encrypt with it. That can't work. With any symmetric scheme, whatever locks also unlocks — if you can encrypt with a secret, you can decrypt with it too. So you'd be able to reopen the file, which defeats the whole purpose.

The primitive that separates "can lock" from "can unlock" is public-key cryptography. Your friend holds a key pair:

Step by step

  1. Your friend creates a lock codeThey pick a password. friend-lock stretches it with Argon2id into a 32-byte seed, and deterministically derives an X25519 key pair from that seed. You receive only the public key (plus a random, non-secret salt), packed into a short lock code.
  2. You lock the filefriend-lock zips your file(s), then encrypts the zip to your friend's public key using a libsodium sealed box. A sealed box generates a throwaway ephemeral key pair, encrypts with it, and discards the ephemeral private key — so nobody, not even you, can decrypt afterwards. Only the recipient's private key can.
  3. Your friend unlocksThey enter their password, friend-lock re-derives the exact same private key (same password + same salt → same key), opens the sealed box, and unzips the original file(s).
The salt and Argon2id parameters travel inside the locked file, so your friend only ever needs to remember the password. A salt is not secret — it just makes each password's derived key unique.

The building blocks

PurposeWhat we use
Turn a password into a key (slowly, on purpose)Argon2id — winner of the Password Hashing Competition; the current OWASP-recommended default
Public / private key pairX25519 (Curve25519), seeded deterministically from the password
Encrypt so only the recipient can openSealed box — X25519 + XSalsa20-Poly1305 authenticated encryption
Bundle files / foldersZIP (preserves names and structure), encrypted as one blob

All cryptography is provided by libsodium (the audited -sumo build), running as WebAssembly in your browser.

The "it's just a photo" carrier

The locked output is a real, viewable .jpg: a cover image with a short notice and a QR code. A JPEG officially ends at its end-of-image marker, and viewers ignore anything after it — so the encrypted data is appended there. Open the file in any photo viewer and you see the picture; drop it into friend-lock and it reads past the image and decrypts. A plain .flock download is offered too, for channels that re-compress images.

Transfer tip: send the .jpg as a file attachment, not as an in-chat photo. Messengers like WhatsApp or Telegram re-compress images and would strip the hidden data. Use the .flock file for those.

File formats

lock code    = base64url( u8 version | u32 ops | u32 mem | 16B salt | 32B public key )
.flock blob  = "FLK1" | u8 version | u32 ops | u32 mem | 16B salt | sealed ciphertext
.jpg carrier = <valid JPEG cover> | .flock blob | "FLCKPLD1" | u64 payload length

Privacy — where everything runs

friend-lock is a single static web page. All processing happens in your browser. Your files and passwords are never uploaded — there is no server to upload them to, no database, no account, and no tracking. You can even save the page and use it fully offline. See our privacy note for details.

Security notes & disclaimer

No warranty. friend-lock implements current, well-established cryptographic guidelines to the best of our ability, but it is provided “as is”, without any warranty of any kind. We make no guarantee about its encryption strength or fitness for any purpose, and accept no responsibility or liability for any loss, disclosure, or damage arising from its use. You use it entirely at your own risk. It has not undergone a formal external security audit. For high-stakes secrets, consult a security professional.