How it works

The short version: your passphrase never leaves your device, and every key that could open your photos is derived from it. What we hold is unreadable to us.

The scheme, exactly

kek        = PBKDF2-HMAC-SHA256(passphrase, salt || "photosafe-kek-v1",  600000, 32 bytes)
auth_hash  = PBKDF2-HMAC-SHA256(passphrase, salt || "photosafe-auth-v1", 600000, 32 bytes)
master_key = 32 random bytes, generated once, in your browser
wrapped_mk = nonce(12) || AES-256-GCM(kek, master_key)      <- this is what we store

per photo:
file_key   = 32 random bytes
ciphertext = nonce(12) || AES-256-GCM(file_key, photo)      <- this is what we store
wrapped_fk = nonce(12) || AES-256-GCM(master_key, file_key) <- this is what we store
meta_blob  = nonce(12) || AES-256-GCM(master_key, filename+date+type)

The browser implementation is /static/js/crypto.js; the identical Python implementation is crypto_core.py. Both are short enough to read in full, and you should, because a security claim you cannot check is a marketing claim.

What we can see anyway — the honest list

End-to-end encryption hides content. It does not hide everything, and any service that tells you it does is lying. We can see:

We cannot see: filenames, dates, album names, image contents, thumbnails, or anything derived from them.

Where the bytes live

During the beta, ciphertext is stored on a Hetzner Storage Box in Germany — one physical location, not a multi-region object store — with Cloudflare R2 wired in as the overflow and available as a second copy. Either way the server only ever sees ciphertext: which backend a given file landed on makes no difference to what we can read, which is nothing. The metadata index is a small database on our own server; every object also carries an encrypted sidecar on every configured backend holding everything needed to rebuild that index, so losing the database — or losing one backend outright — does not lose your library.

Durability, honestly

A Storage Box is not raided across data centres the way R2 or Hetzner Object Storage are. What protects you against it:

Compared with the alternatives

ServiceWho can read your photosOpen source clientExport
Google Photos / iCloud PhotosThe provider (iCloud only with Advanced Data Protection enabled, which is off by default)NoTakeout / manual, bulk and slow
Amazon Photos, Dropbox, pCloud (standard)The providerNoYes, manual
Ente PhotosOnly youYesYes, desktop app
Immich (self-hosted)Only you — because it is your serverYesYes, it is your disk
PhotoSafeOnly youYes — the client is on this siteOne button, plus an offline restore script

We are not the only honest option here, and we will not pretend to be. Ente is a mature, audited, end-to-end encrypted product with real mobile apps, and if you need an iPhone app today you should use it. Immich is free if you are willing to run a server. PhotoSafe's case is a flat price, a format you can read without us, and an export that is a first-class feature rather than a retention obstacle.

What we have not done