Skip to main content
Your files are encrypted on your device and decrypted on the other person’s. Nothing in between can read them, and that includes Floe’s own servers. This is what encrypted end to end means. It rests on the introduction: each device has to get the other’s real ID through Floe’s server. A link key checks that on a link that carries one, and What it does not protect against says how far that goes. There is nothing to switch on. It is not a mode, an upgrade, or a setting. Every transfer works this way, direct or relayed, on floe.one or on an instance you run yourself.

Three things that follow from that

The keys exist only on the two devices. They are generated fresh for each transfer, live in the two browsers or apps involved, and are thrown away when the connection closes. There is no key server, no spare copy of the keys held anywhere, and no recovery: once a transfer is over, that transfer’s keys are gone and cannot be reconstructed by anyone, Floe included. The servers handle the introduction, not the content. The signaling server passes connection details between the two devices for a few seconds and then plays no further part. It is not on the path the file takes. When a relay is involved it is on the path, but only ever carrying encrypted packets it has no way to open. Self-hosting does not change any of this. The encryption is a property of the connection between the two devices, not of who runs the server. If you run your own instance you get the same guarantee, and the introduction then runs on a server you operate. What the link key cannot see says what that does and does not settle.

What it does not protect against

Encryption answers “can anyone in the middle read this”. It does not answer every question, and the honest limits are worth knowing rather than discovering. The one that matters most is the introduction. Each device sends the other a short ID for its encryption key, and those IDs pass through the signaling server. A server that wanted to could hand each side an ID of its own instead, sit in the middle, and read everything. A link key is Floe’s check for that. A link from the web app, from floe 1.12 and later, or from Floe Desktop 1.1 and later carries one after the #, and no server receives it. Once the devices connect, each side that holds it proves so, with a proof tied to the certificates actually in use. A receiver that holds the link key refuses a sender that cannot prove it, before any file name or byte. A server in the middle does not hold the link key, so it cannot pass.
That check does not cover everything, and the server is still part of what you rely on. A room code carries no link key, and neither does an older link. The web app’s Send page, floe send 1.12 and later and Send in Floe Desktop 1.1 and later only detect, so a server playing a receiver with no link key gets the whole file. Whoever serves the web app’s JavaScript, and anyone who held the whole link, can pass the check. Where it matters, encrypt the file yourself before you send it.
Read Known limitations for that and the others in plain language. A privacy claim is worth more when the exceptions are published alongside it.

How the encryption works

This section is the technical detail, and you can skip it: nothing in it changes what the sections above say. Floe uses WebRTC data channels, which run SCTP, the protocol that carries the data, over DTLS. DTLS is TLS adapted for separate packets (datagrams): the same cipher suites and the same handshake, over a transport that does not guarantee ordering. This is distinct from DTLS-SRTP, which is what WebRTC uses for audio and video. Each peer generates a certificate and key pair for the session. The short ID from the previous section is the certificate fingerprint, a short checksum of that certificate. The fingerprints are carried in the connection-setup messages, the SDP offer and answer, and the DTLS handshake verifies the certificate it receives against the fingerprint it was promised. An attacker sitting on the network path cannot substitute a certificate, because they cannot also change the fingerprint that arrived through the signaling channel. An attacker who controls the signaling channel itself can. A link key is the check on that last case. Once DTLS is up, each side that holds the link key sends an HMAC, a hash made with a secret key, over the room id and the hashes of both certificates DTLS actually used. A server in the middle runs two DTLS connections with certificates of its own. A proof from one of them fails on the other, and it cannot make a new one without the link key. The exact frame is under kc. Keys are short-lived and per-session. They are created when the connection is created and discarded when it closes. Floe adds no encryption layer of its own on top of this. Integrity in transit comes from DTLS. On top of that, the receiving app checks each finished file against the size the sender announced and, when the sender provides one, against the sender’s SHA-256 of the file. See File checks.
Last modified on November 3, 2026