Security model
This page states plainly what protocol version 3 (rChat 2.0.0) does and does not protect. It summarises rChat’s threat model; the whitepaper has the full threat model and the details.
What is protected
Section titled “What is protected”- Message content. Messages are encrypted on the phone with keys agreed by a hybrid handshake (X25519 together with the post-quantum ML-KEM-768) and advanced by the Double Ratchet, using XChaCha20-Poly1305. The relay passes on ciphertext it cannot decrypt.
- Recorded traffic, against a future quantum computer. Every conversation and every message request mixes an ML-KEM-768 secret with X25519 end to end, so someone who records traffic today and later has a quantum computer still has to break both. The connection to the relay also uses a hybrid post-quantum key exchange (X25519MLKEM768), which protects the metadata the link carries in the same way; message content does not depend on it. Only the key exchanges are post-quantum: the signatures that prove who someone is (Ed25519, and the device key’s P-256), the relay’s certificate and identity, and the connection proofs are classical, so they resist forgery today but not an attacker who already has a quantum computer when you connect. See TLS and certificates.
- Forward secrecy of messages. Each message uses a fresh key, so a key compromised later does not expose earlier messages. The post-quantum part of each handshake uses fresh keys that are wiped after use. This does not cover requests and their first messages (see below).
- Integrity and binding. Every message authenticates its header and both people’s identity keys, so it only decrypts for the pair it was written for.
- Transport. Connections use TLS 1.3 only, with no TLS 1.2 and no plaintext fallback (see TLS and certificates).
- Logs. At the default level the relay logs no identifiers, IP addresses or content (see What the relay logs and stores).
Key authentication
Section titled “Key authentication”- Signed keys. Each account’s keys (identity, agreement and ML-KEM) are signed with its identity key. rChat refuses to start a conversation with keys that are not, so the relay cannot swap in keys of its own. Each request to open a conversation also signs its own one-time keys, so the relay cannot slip in a post-quantum key it could decrypt.
- Proof bound to the TLS session. When the app publishes its keys, it signs the relay’s fresh challenge together with a value taken from the TLS session (a TLS exporter). The relay only routes to, and delivers queued messages to, a connection that proved the identity. A proof copied to another connection fails, and a resumed TLS connection proves again. This is also why TLS must terminate at the relay (see Behind a TCP front end).
- Pinning is accepting. When you add someone by scanning their code, rChat remembers their keys and will not talk to them under different keys. A mismatch shows “Keys don’t match” and stays until you scan their code again. Contact codes carry the post-quantum key too, so they are about 1.7 KB, and codes from older versions are refused.
- First use. If someone first reaches you through a request, rChat cannot tell who is behind their key. Contact Info shows “Keys from their first message”. Scanning their code in person, or comparing safety numbers, is how you know.
- Safety numbers. You can compare a 60-digit safety number with a contact, in person or on a call, to check that each of you has the other’s real keys. One phone can show it as a QR code for the other to scan. If their keys later change, the “compared” mark is removed. Safety numbers did not change with protocol v3.
- Key rotation. If you rotate your keys, your contacts follow automatically only when the notice is signed by your previous keys, so anyone who has stolen your previous keys could do the same. Rotation does not recover a stolen account: use Reset Identity instead.
Delivery and recovery
Section titled “Delivery and recovery”- Stored sessions. Each phone saves its conversations’ encryption state, sealed under a key that only that phone can use, and excluded from backups. An app restart loses no message the relay accepted (except messages being handed over at that moment), and a replayed message is never decrypted twice. A relay restart loses the messages the relay was holding in memory, unless its operator turned on encrypted persistence.
- Truthful status. Sent means the relay took the message. Delivered means the contact’s phone stored it, reported by an end-to-end encrypted receipt the relay cannot forge. See Delivery and recovery.
- Lost state is reported inside the conversation. When a phone loses its sessions (a reinstall, a new phone), it tells each contact which messages it could not read, inside a new session made with the pinned keys. The relay cannot forge that notice; it can only drop it, and the sender then keeps seeing Sent.
- Automatic resend needs the contact’s phone. A message is resent automatically only when the notice is signed by the contact’s device key: a key in their phone’s secure hardware (or a software key where there is none; see Known limits), pinned only when you scan their code in person (or paste it to add a brand-new contact). It also needs no key change since the message was sent, a message under 72 hours old that was never delivered, and at most 50 automatic resends per contact per day. Otherwise the message shows Not delivered and you tap Resend. Someone with a stolen copy of a contact’s account keys, but not their phone, cannot make your phone resend anything automatically.
Relay identity and invites
Section titled “Relay identity and invites”The usual way to join a relay is its invite: a link or QR code from the relay’s operator that carries the relay’s address and identity. rChat pins that identity straight away, so even the first connection is checked. An invite contains the relay’s secret address, so it lets the holder reach the relay; it never lets anyone read messages.
Without an invite, rChat remembers your relay’s identity after the first connection and stops connecting if it changes without a handover signed by the old identity. That first connection has to be trusted, unless you enter the relay’s identity yourself and turn on Require a saved server identity. See Relay identity.
Message requests
Section titled “Message requests”A conversation opens only when both people have asked for it. Someone who has your code but whom you haven’t accepted can’t see whether you’re online, and receives nothing from you until you accept. Their request may carry one short first message.
Requests are sealed with ML-KEM-768 and X25519 together, so a recording alone, even with a future quantum computer, does not open one. Requests and their first messages are still not forward-secret. They are encrypted with keys derived from the recipient’s long-term keys, so anyone who recorded a request and later obtains those keys can read its first message.
Blinded pairing
Section titled “Blinded pairing”After your first conversation with someone, your phones reconnect using a code that only the two of you can compute. It changes every 10 minutes and every time you come back online, and the relay keeps only a scrambled form of it, so a relay that records requests can’t use the code to link two of yours made more than about 20 minutes apart. A conversation is never resumed by its old circuit. While a conversation is open, the relay’s memory still links its two members (as it did before). Once both have been gone about 10 minutes, nothing it keeps names the pair; waiting blind asks name no one; and no token or circuit id links one connection period to the next.
- When your phone still names who it wants to reach: first contact, after one of you reinstalls or gets a new phone, after a key rotation, and as a fallback after a full day without reconnecting the blinded way. The relay can force at most one such named request per pair of people per day.
- Limits. Someone watching the relay while it runs can still see two accounts connect to each other at the same moment. While a conversation is open, the relay routes it between two known connections and its memory links the two of you. A contact can tell that you have reconnected. A phone whose clock is more than 5 minutes off the relay’s can’t connect at all (phones normally keep network time), so any two connected phones are close enough in time to reconnect without naming each other.
Traffic analysis
Section titled “Traffic analysis”- Padding is mandatory. Every message and receipt is padded to a size bucket (256 B, 1 KiB, 4 KiB, 16 KiB, then 64 KiB steps), and every request is exactly 5120 bytes. Named and blinded requests to open a conversation are the same size. The relay still sees the size bucket.
- Receipts travel end-to-end encrypted, like messages, and are sent with a short random delay in small batches. The relay may still infer that a receipt was sent from its timing.
- Steady traffic is an optional setting, off by default. While the app is open it sends one same-size packet at a fixed rhythm to a randomly chosen open conversation, so the timing of your messages reveals less. It works fully only when the person you’re talking to uses it too, and photos, files and voice messages go outside it.
- Extra traffic protection is the lighter optional setting, off by default. It sends extra dummy traffic while the app is open, which makes it somewhat harder for the relay to tell when you’re messaging. It doesn’t hide timing, and it lets people you have open conversations with see when rChat is open. Steady traffic replaces it while on.
- Reconnects resume their TLS session, so they look like any other returning client. A network observer can link two connections, made up to 12 hours apart, when the second presents a resumption ticket from the first (tickets are used once and kept in memory only).
- The relay’s decoy website keeps a casual scan from seeing what runs on the port, and since 2.0.0 every relay’s decoy is different (see Configuration guide). A determined active prober can tell it apart from a real web server. rChat’s traffic is not disguised as a web browser’s.
What the relay learns
Section titled “What the relay learns”While it is running, the relay can see which accounts are connected, when, and from which IP address, and which two of them have a conversation open. When two people first connect, or after one of them gets a new phone or changes keys, it can also see for up to ten minutes which account is trying to reach which. It does not write this to its logs.
- It sees the size bucket, timing and direction of each packet in an open conversation, including the moment a request is accepted.
- A request waiting for someone who is offline is held in memory until it is delivered, for at most 72 hours.
- Messages for someone who is offline are held in memory for at most 72 hours and deleted once delivered. They are filed under the recipient; the sender’s identity is inside the encrypted message.
- A background check looks like a short connection with no conversations.
- The relay receives no data about key rotation, but it can usually link a rotated identity to the old one, because the new identity contacts the same people straight away.
Anyone who operates, seizes or gains root on a running relay can read the connected accounts, and which of them share open conversations, from its memory. That is a reduction, not protection.
Denial of service
Section titled “Denial of service”The relay can always refuse, drop, delay or reorder traffic. Its own defences are on the resource limits page. These gaps concern disrupting delivery; none helps anyone identify a user or read a message:
- Request floods. A sustained flood of requests from many sources can crowd older requests out of a full request store. Proof of work is future work.
- Shared addresses. Fair shares are per IPv4 address or IPv6 /48, so many users behind one carrier-grade NAT address share one share, and that address can be the one that is shed.
- Slow-consumer harassment. An accepted contact can send at the rate-limited maximum. A recipient that cannot keep up is disconnected and its messages are held offline.
- Offline queue filling. An accepted contact can fill a recipient’s offline queue while they are away, so other senders are refused until the recipient reconnects or messages expire. Steady-traffic packets may fill at most half of it.
Known limits
Section titled “Known limits”- Device seizure. Someone who seizes your unlocked phone, or copies the app’s files together with their key, can read messages still waiting at the relay under the current keys, and future messages until both phones complete a fresh key exchange step.
- Phones without secure hardware. Where there is no Secure Enclave (older iOS Simulators), the device key is a software key in the Keychain. Extracting both the account keys and that key from such a device would pass the automatic-resend check. Contact Info says “Their device key isn’t stored in secure hardware.” for such a contact.
- New phone, old device key. When a contact moves to a new phone, you keep their old device key until you scan their new code, so recovery falls back to a tap on Resend. This fails safe.
- Queue hand-over. A phone killed while the relay is handing it its waiting messages loses those messages. There is no acknowledgement from the phone to the relay; the sender keeps seeing Sent, which is true.
- Rollback. Someone with write access to the app’s files can roll the saved state back to an older copy. This is a device compromise and is not defended beyond iOS Data Protection.
- Inflated counts. Forged packets can inflate the “couldn’t be decrypted” count on the receiving phone. That is denial of service only, and it is capped.
- First contact. A contact who first reached you through a request is trusted on first use until you scan their code or compare safety numbers.
- Message sender envelope. The outer envelope of an ordinary message hides the sender from the relay with X25519 only; the post-quantum protection is in the conversation itself and in requests.
- Disappearing messages and alerts. See Media and disappearing messages and Notifications for what they do not cover.
Not implemented
Section titled “Not implemented”Key transparency, post-quantum signatures, proof of work for requests, and reproducible builds.