TECHNICAL DOCUMENTATION

How Offline works

Offline is an end-to-end encrypted messenger designed to leave nothing behind. This page explains the cryptography layer by layer, what the server can and cannot see, and the layers that protect not just your messages but who you talk to.

01Your identity is a key

When you first open the app, an ECDH key pair on the P-256 curve is generated locally on your device. The private key never leaves the device. Your "account" is, in practice, the public key — there is no username, password, or phone number.

Your ID (a UUID) simply points to your public key on the server, so others can fetch it to write to you. A public key cannot decrypt anything; it can only be used to encrypt messages addressed to you.

02Sending a message

Messages are protected by a Double Ratchet — the same construction used by the Signal Protocol. There is no out-of-band handshake: the ratchet is bootstrapped from the long-term ECDH shared secret between your two identity keys, so the very first message already ratchets.

  1. Root key — an initial ECDH (your identity private key × their identity public key) is run through HKDF-SHA-256 to seed the ratchet's root key.
  2. Symmetric ratchet — every message advances a chain key via HMAC-SHA-256, deriving a fresh one-time message key. The chain only moves forward; previous message keys are discarded immediately.
  3. DH ratchet — whenever a new ratchet public key is seen, a fresh ECDH + HKDF-SHA-256 derives a new root key and chain key. This is what gives the ratchet its self-healing property.
  4. AES-256-GCM — the message is sealed with the one-time message key. GCM provides confidentiality and integrity together: the ciphertext cannot be altered without detection.

Out-of-order and missed messages are handled by tracking skipped message keys (up to a bounded limit), so delivery delays never break decryption.

Wire format

A ratchet message is transmitted in a compact, newline-separated wire format:

DR1format version tag (Double Ratchet)
<dhPubB64>sender's current ratchet public key (SPKI, base64)
<sendCount>message number in the current sending chain
<prevChainCount>length of the previous chain — lets the recipient recover skipped / out-of-order messages
<ivCtB64>IV + ciphertext (base64) — the AES-256-GCM output

Five lines: DR1\n<dhPubB64>\n<sendCount>\n<prevChainCount>\n<ivCtB64>

Cover traffic (see below) uses a lighter single-shot scheme tagged FS1 — a fresh ephemeral ECDH key per packet — since it carries no real conversation state to ratchet.

03Forward secrecy & post-compromise security

Because each message key is derived from a ratchet step and destroyed right after use, Offline provides forward secrecy: someone who later steals your long-term key still cannot decrypt past messages — the keys that protected them no longer exist anywhere.

The DH ratchet adds the converse guarantee, post-compromise security (self-healing): if a device is compromised at some point, the conversation automatically recovers once a new DH ratchet step happens, locking the attacker back out of all future messages.

04Group messages

A group conversation uses a shared symmetric group key, generated locally on a member's device. That key is distributed to each member end-to-end — encrypted individually to each member's public key — so it is never exposed in the clear. Group messages are then encrypted with the group key using AES-256-GCM.

The server only ever relays the encrypted key material and the encrypted group messages. It never sees the group key, the membership beyond routing IDs, or any content.

05Sealed sender

The relay needs a recipient ID to route a message, and it forwards the sender ID so the recipient's app can match an incoming message to a known contact. But it never persists who sent what: the offline queue (for messages to someone currently disconnected) stores only the recipient ID and the ciphertext, and error logs never include sender identity.

The recipient independently verifies the real sender by checking the sender public key carried inside the encrypted envelope against their stored contact — so routing never has to be trusted for authenticity.

06What the server sees — and doesn't

The server only handles ciphertext plus routing metadata (which IDs, packet size, timestamp). It can never read content, because it holds no private key. This is the whole premise:

The core guarantee

The server can't leak what it doesn't have. No private keys, no plaintext, no message content — ever.

07Anti-traffic-analysis

Beyond content, Offline adds layers against an observer trying to learn who you talk to, not just what you say:

08Calls

Voice and video go peer-to-peer over WebRTC with encrypted media. When a direct connection isn't possible, encrypted media is relayed through a TURN server that sees only ciphertext — TURN access uses short-lived HMAC-SHA1 credentials, never a static password. The server only ever sees signaling, never call content. You can verify your peer's key fingerprint mid-call to rule out a man-in-the-middle.

09Message types

A subtle but important detail: in the protocol, multiple message types — msg, call, del, rea, and others — are all handled as encrypted payloads. The recipient must decrypt each one before acting on it.

This is, by design, true even for control signals like delete-for-everyone and reactions: the server can't tell a "delete" from a "thumbs up" from a paragraph of text. Everything is ciphertext until it reaches the recipient's device.

10Cryptographic primitives

Offline uses only standard, audited primitives via the platform Web Crypto API — there are no hand-rolled crypto implementations:

This documentation is informational and describes the system's design. Some features (federated mixnet, native apps) are roadmap targets and not yet live. Cryptography descriptions reflect the current implementation and may evolve as the protocol is hardened.