How the security works

Written so you can check it, not so you'll trust it.

What's encrypted, and where

Messages, photos, files and voice notes between contacts are encrypted on your phone, with keys that exist only on your phone and your contact's.

A conversation starts with an X3DH key agreement: four Diffie-Hellman exchanges combining both identity keys, a fresh ephemeral minted for that session, a signed prekey that rotates weekly, and a one-time prekey that is destroyed the moment it is used. That means the starting secret is different every time a session opens, and once those prekeys are gone, nobody can reconstruct it — not us, not someone holding both identity keys and a recording of every message ever sent.

From there a double ratchet takes over: a fresh key for every message, with the material needed to recompute earlier keys destroyed as it is used. The ratchet header — which would otherwise let us group a conversation's messages together even without knowing who sent them — is encrypted along with the message, so what reaches our disk is an indistinguishable blob and thirty-two random bytes that never repeat.

When both phones run iOS 26 or later, the key agreement also mixes in ML-KEM-768, a post-quantum algorithm standardised by NIST, so a recording of today's traffic can't be decrypted later by an attacker with a quantum computer as long as either algorithm holds. If either phone is older, the conversation is classical-only, and the encryption screen inside the app says which one you have — per conversation, not as a blanket promise.

What our server can see

The server is a relay and a directory. It knows: that your account exists (a random ID and the display name you chose), your latest position while the app is open (held in memory only, never written to disk, and stopped being used sixty seconds after your last update), who your contacts are, your notification token, an email address if Sign in with Apple gave us one, the public key material your phone publishes so people can start conversations with you (a signing key, a weekly signed key, and a pool of single-use keys), a hash of each device that has signed in, and it holds your messages as ciphertext it cannot read. While you are connected it also sees the shape of your traffic: that the app is in the foreground, that you are looking for people nearby, and the control messages your phone and a contact's exchange — a delivery confirmation, a screenshot alert, a request to rebuild encryption. Each names a contact and says nothing about what passed between you. Sealed messages are stored with no sender — though the conversation itself records which of you opened it. Photos and files are forwarded piece by piece when both phones are connected and forgotten as they pass; if the recipient is offline, the encrypted copy — unreadable to us — is held for up to 48 hours, along with its filename and who sent it, then deleted.

What a subpoena would get

The honest answer, in full: your account ID and display name, your contact list, unreadable ciphertext, your notification token, your Apple sign-in identifier and any email address Apple gave us, which of you opened each conversation, the filenames and senders of any attachments we happen to be holding at that moment, and the text of any report either of you filed — which is readable, because a human has to review it.

Not on that list: message content, location history, and a message-by-message record of who wrote what. We can't hand over what we never had, and we would rather list what we do have than let the sentence do the work.

What being there adds

You can add someone from anywhere with an invite link, and that conversation is encrypted exactly like every other one. Standing next to them is not a requirement — it is the stronger of the two ways, and this is what it buys.

When you add someone standing near you, the two phones open a short local link — Bluetooth or peer-to-peer Wi-Fi, with our server nowhere in it — and hand each other their public keys. Each phone then compares the key it was given directly against the key our server supplied for that person. Differing has no innocent explanation, and the phone that spotted it tells you, marks the contact untrusted, and asks you to check the safety words in person. Matching is weaker than it sounds and we would rather say so: it rules out a key we substituted after the fact, but the same server told your phone who was standing nearby, so it cannot rule out a server that pointed you at the wrong person from the start. The same-room sound check is what closes that, because the code it plays is derived from the two identity keys and we never hold either. Note that only the phone which received the mismatching key can see the problem — it is not relayed to the other side, because the relay is precisely what is in question.

The remote path is not a downgrade in encryption, only in proof. An invite link carries the key inside the link itself, so if that link reaches your friend over a channel we don't run and their phone opens it directly into the app, we never had the opportunity to substitute the key you sent.

That guarantee runs in one direction only, and it is worth being exact about which. Your key travels inside the link. Theirs comes back to you through our server, unsigned — so on the invite path we could substitute the key you receive, even though we could not substitute the one you sent. Nothing about the link fixes that, and no amount of care with how you send it does either. The same-room check is what closes it, which is why on this path we treat it as the step rather than an optional extra.

One caveat worth stating: if the link is opened as a web page instead — no app installed, or a tap in a desktop browser — that request does reach our server, and the page we serve is what reads the key out of it. Scanning the QR code, or letting the link open the app, avoids that.

We should be precise about the limits. If the local link can't be established — permission declined, Bluetooth off, phones not close enough — the app falls back to using the key our server supplied, and it says so: the contact is marked "Added nearby" rather than "Keys traded in person", and that description states plainly that the key came through us. The in-person tone check is what settles it in that case, because sound travels between the phones without touching our server. We would rather show you a weaker label than a false one.

Which raises the obvious question: if we hold the directory, why can't we fake the sound too? We can compute it. The code is derived from the secret the two phones share, and on a conversation whose key we had substituted we would know that secret and could work out the same code. What we cannot do is make a noise in your room.

So the rule the app enforces is the narrow one that follows from that: a phone is only ever convinced by a code it heard through its own microphone. Not by a message from us saying the other phone heard it — we could write that message. Not by hearing its own speaker, which would let one phone alone pass the check with nobody else present. The phone refuses any listening window its own speaker was active in, and discards it. That is why both phones play: each one needs evidence of its own, and being told about someone else's is not evidence. It is also why the check takes fifteen seconds or so rather than being instant — the faster version was the one that counted its own echo.

When a phone starts over

Delete the app and reinstall it and your phone has forgotten every conversation key it held. The other side has not, and until recently that mismatch was permanent — messages simply stopped arriving with nothing to say why.

The two phones now negotiate a fresh session directly. Each conversation carries a generation number, whichever side is entitled to mint a new secret does so, and the higher number always wins. There is nothing to negotiate and no way for the two to disagree indefinitely. Anything you sent that the other side could not read is sent again automatically, so a reinstall costs you a few seconds rather than the conversation.

Check it yourself

Inside the app, Settings → What our server knows shows you your own record live from our database, including the raw stored form of your last message. If it starts with e2: or e3:, that's what we have — and what anyone who took a copy of our database would have.

Honest limits

← StrongChat · Privacy policy · Terms