Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.
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.
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.
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.
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.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Floe","colors":{"primary":"#00A3C9","light":"#B1DDEB","dark":"#00A3C9"},"logo":{"light":"https://mintcdn.com/floe/ezxgMLrxNnA-g95b/logo/dark.svg?fit=max\u0026auto=format\u0026n=ezxgMLrxNnA-g95b\u0026q=85\u0026s=8cafdf2bfd539f368800c1e9da5d5bb6","dark":"https://mintcdn.com/floe/ezxgMLrxNnA-g95b/logo/light.svg?fit=max\u0026auto=format\u0026n=ezxgMLrxNnA-g95b\u0026q=85\u0026s=ad3f72234c662bb74789973c72e8aad3","href":"https://floe.one"},"favicon":"https://mintcdn.com/floe/6X_YOmQ2pusH4WDb/favicon.svg?fit=max\u0026auto=format\u0026n=6X_YOmQ2pusH4WDb\u0026q=85\u0026s=949d06424d1d51054ac221f2c4a36f61","appearance":{"default":"dark","strict":false},"navbar":{"links":[{"icon":"arrow-up-right","href":"https://floe.one","label":"floe.one"}],"primary":{"type":"github","href":"https://github.com/jannskiee/floe"}},"footer":{"socials":{"github":"https://github.com/jannskiee/floe"},"links":[{"header":"Product","items":[{"label":"Floe","href":"https://www.floe.one"},{"label":"Download","href":"https://www.floe.one/download"},{"label":"How It Works","href":"https://www.floe.one/how-it-works"}]},{"header":"Documentation","items":[{"label":"Quickstart","href":"https://www.floe.one/docs/quickstart"},{"label":"Web app","href":"https://www.floe.one/docs/web-app/sending"},{"label":"CLI","href":"https://www.floe.one/docs/cli/installation"},{"label":"Desktop app","href":"https://www.floe.one/docs/desktop/installation"},{"label":"Self-hosting","href":"https://www.floe.one/docs/self-hosting/overview"},{"label":"FAQ","href":"https://www.floe.one/docs/faq"},{"label":"Changelog","href":"https://www.floe.one/docs/changelog"}]},{"header":"Project","items":[{"label":"GitHub","href":"https://github.com/jannskiee/floe"},{"label":"Releases","href":"https://github.com/jannskiee/floe/releases"},{"label":"Report an Issue","href":"https://github.com/jannskiee/floe/issues"},{"label":"Contributing","href":"https://github.com/jannskiee/floe/blob/main/CONTRIBUTING.md"},{"label":"Sponsor","href":"https://github.com/sponsors/jannskiee"}]},{"header":"Legal","items":[{"label":"Privacy Policy","href":"https://www.floe.one/privacy"},{"label":"Terms of Use","href":"https://www.floe.one/terms"},{"label":"Security Policy","href":"https://github.com/jannskiee/floe/security/policy"},{"label":"License (MIT)","href":"https://github.com/jannskiee/floe/blob/main/LICENSE"}]}]},"search":{"prompt":"Search the Floe docs"},"seo":{"metatags":{"og:type":"website","og:site_name":"Floe","og:image":"https://floe.one/og.png","twitter:card":"summary_large_image","twitter:image":"https://floe.one/og.png"}},"fonts":{"family":"Geist"},"icons":{"library":"lucide"},"styling":{"codeblocks":"system","latex":false},"contextual":{"options":["copy","view","chatgpt","claude"],"display":"header"},"metadata":{"timestamp":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"floe","hasAudioNarration":false,"actualSubdomain":"floe","customDomains":["www.floe.one"],"gitSource":{"type":"github","owner":"jannskiee","repo":"floe","deployBranch":"main","contentDirectory":"docs","isPrivate":false,"mountPath":"","label":""},"feedback":{"thumbs":true,"edits":true,"issues":true},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6aedf1862f3197cf5b964f64","clientVersion":"0.0.4087","searchFilterCounts":[{"language":"default","tag":"Self-hosting","count":12},{"language":"default","tag":"How Floe works","count":8},{"language":"default","tag":"CLI","count":7},{"language":"default","tag":"Desktop app","count":6},{"language":"default","tag":"Reference","count":5},{"language":"default","tag":"Getting started","count":3},{"language":"default","tag":"Help","count":3},{"language":"default","tag":"Web app","count":3},{"language":"default","tag":"Changelog","count":1}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"/docs","hasChatPermissions":true,"hasWebMcpPermissions":true,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":true},"customCss":[{"filePath":"style.css","content":"[data-component-part=\"update-tag\"]:not(:last-child)::after{content:\"\\00B7\";margin-inline-start:0.3em;opacity:0.5}#footer img.nav-logo{height:44px;width:94.6px;object-fit:cover;object-position:left center;margin-top:-12px}#footer a:not([href*=\"mintlify.com\"]){color:rgb(10 10 10 / 0.62)}#footer a:not([href*=\"mintlify.com\"]):hover{color:rgb(10 10 10 / 0.85)}.dark #footer a:not([href*=\"mintlify.com\"]){color:rgb(255 255 255 / 0.62)}.dark #footer a:not([href*=\"mintlify.com\"]):hover{color:rgb(255 255 255 / 0.85)}#footer a[href*=\"mintlify.com\"]{color:rgb(110 110 110)}.dark #footer a[href*=\"mintlify.com\"]{color:rgb(140 140 140)}.dark #footer a>svg[aria-hidden=\"true\"]{background-color:rgb(140 140 140)}#footer button:not([class*=\"bg-gray\"]){color:rgb(110 110 110)}.dark #footer button:not([class*=\"bg-gray\"]){color:rgb(140 140 140)}#footer a[rel=\"noreferrer\"]{padding-block:2px}#footer a:has(>svg[aria-hidden=\"true\"]){display:inline-flex;align-items:center;justify-content:center;min-width:24px;min-height:24px;margin-left:-2px}#footer button[class*=\"bg-gray\"]{background-color:rgb(17 17 17 / 0.08);color:rgb(63 63 70)}.dark #footer button[class*=\"bg-gray\"]{background-color:rgb(255 255 255 / 0.1);color:rgb(212 212 216)}[data-component-part=\"card-icon\"] svg{background-color:rgb(17 17 17)}.dark [data-component-part=\"card-icon\"] svg{background-color:#FFFFFF}#sidebar li[data-active=\"true\"] a{color:rgb(17 17 17);background-color:rgb(17 17 17 / 0.1)}.dark #sidebar li[data-active=\"true\"] a{color:rgb(255 255 255);background-color:rgb(255 255 255 / 0.1)}#table-of-contents .toc-item[data-active=\"true\"]>a{color:rgb(17 17 17)}.dark #table-of-contents .toc-item[data-active=\"true\"]>a{color:rgb(255 255 255)}#table-of-contents .toc-item>a:hover{color:rgb(17 17 17)}.dark #table-of-contents .toc-item>a:hover{color:rgb(255 255 255)}[data-component-part=\"tabs-list\"]{--primary: 17 17 17;--color-primary: rgb(17 17 17);--primary-light: 255 255 255;--color-primary-light: rgb(255 255 255)}[role=\"menuitem\"][data-theme-preference]{--primary: 17 17 17;--primary-light: 255 255 255;--color-primary: rgb(17 17 17);--color-primary-light: rgb(255 255 255)}#navbar a:hover,#navbar a:hover span{color:rgb(17 17 17)}.dark #navbar a:hover,.dark #navbar a:hover span{color:rgb(255 255 255)}#navbar a:hover svg[class*=\"forced-colors\"]{background-color:rgb(17 17 17)}.dark #navbar a:hover svg[class*=\"forced-colors\"]{background-color:rgb(255 255 255)}.card:hover{--primary: 17 17 17;--color-primary: rgb(17 17 17)}.dark .card:hover{--primary-light: 255 255 255;--color-primary-light: rgb(255 255 255)}html:not(.dark) #content-area a.link{border-bottom-color:#00A3C9}.chat-assistant-send-button{--primary: 17 17 17;--color-primary: rgb(17 17 17);--primary-dark: 255 255 255;--color-primary-dark: rgb(255 255 255)}.dark .chat-assistant-send-button svg{color:rgb(17 17 17)}#assistant-entry,#assistant-entry-mobile,#ask-assistant-code-block-button,#text-selection-tooltip,.chat-assistant-floating-input,#chat-assistant-sheet{--primary: 17 17 17;--primary-light: 17 17 17;--primary-dark: 0 0 0;--color-primary: rgb(17 17 17);--color-primary-light: rgb(17 17 17);--color-primary-dark: rgb(0 0 0)}.dark #assistant-entry,.dark #assistant-entry-mobile,.dark #ask-assistant-code-block-button,.dark #text-selection-tooltip,.dark .chat-assistant-floating-input,.dark #chat-assistant-sheet{--primary: 255 255 255;--primary-light: 255 255 255;--primary-dark: 255 255 255;--color-primary: rgb(255 255 255);--color-primary-light: rgb(255 255 255);--color-primary-dark: rgb(255 255 255)}.text-tooltip-foreground{background-color:rgb(17 17 17);color:rgb(255 255 255)}.dark .text-tooltip-foreground{background-color:rgb(255 255 255);color:rgb(17 17 17)}[data-testid=\"copy-code-button\"]{--primary: 17 17 17;--primary-light: 255 255 255;--color-primary: rgb(17 17 17);--color-primary-light: rgb(255 255 255)}[data-component-part=\"update-label\"]{--primary: 17 17 17;--primary-light: 255 255 255;--color-primary: rgb(17 17 17);--color-primary-light: rgb(255 255 255)}.dark [data-component-part=\"update-label\"]{--primary: 255 255 255;--color-primary: rgb(255 255 255)}#changelog-filters button.bg-primary{background-color:rgb(17 17 17)}.dark #changelog-filters button.bg-primary{background-color:rgb(255 255 255);color:rgb(17 17 17)}#changelog-filters button.rounded-full:not(.bg-primary):not(.font-medium){background-color:rgb(17 17 17 / 0.06);color:rgb(63 63 70)}#changelog-filters button.rounded-full:not(.bg-primary):not(.font-medium):hover{background-color:rgb(17 17 17 / 0.1)}.dark #changelog-filters button.rounded-full:not(.bg-primary):not(.font-medium){background-color:rgb(255 255 255 / 0.08);color:rgb(212 212 216)}.dark #changelog-filters button.rounded-full:not(.bg-primary):not(.font-medium):hover{background-color:rgb(255 255 255 / 0.12)}#sidebar a:hover,#sidebar a:hover span{color:rgb(17 17 17)}.dark #sidebar a:hover,.dark #sidebar a:hover span{color:rgb(255 255 255)}#content-area>div.my-8.flex.flex-col a{color:rgb(17 17 17 / 0.72)}#content-area>div.my-8.flex.flex-col a:hover{color:rgb(17 17 17)}.dark #content-area>div.my-8.flex.flex-col a{color:rgb(255 255 255 / 0.72)}.dark #content-area>div.my-8.flex.flex-col a:hover{color:rgb(255 255 255)}#content-area table:has(thead th:nth-child(4)) td{min-width:6.5rem}#content-area [data-table-wrapper]>[data-overflow-x-end]:not([data-overflow-x-start]){-webkit-mask-image:linear-gradient(to right, #000 calc(100% - var(--scroll-area-fade-size, 32px)), transparent);mask-image:linear-gradient(to right, #000 calc(100% - var(--scroll-area-fade-size, 32px)), transparent)}#content-area [data-table-wrapper]>[data-overflow-x-start]:not([data-overflow-x-end]){-webkit-mask-image:linear-gradient(to left, #000 calc(100% - var(--scroll-area-fade-size, 32px)), transparent);mask-image:linear-gradient(to left, #000 calc(100% - var(--scroll-area-fade-size, 32px)), transparent)}#content-area [data-table-wrapper]>[data-overflow-x-start][data-overflow-x-end]{-webkit-mask-image:linear-gradient(\n to right,\n transparent,\n #000 var(--scroll-area-fade-size, 32px),\n #000 calc(100% - var(--scroll-area-fade-size, 32px)),\n transparent\n );mask-image:linear-gradient(\n to right,\n transparent,\n #000 var(--scroll-area-fade-size, 32px),\n #000 calc(100% - var(--scroll-area-fade-size, 32px)),\n transparent\n )}#content-area :not(pre)>code:not(td code){display:inline-block;max-width:100%;word-break:normal;overflow-wrap:anywhere}#table-of-contents:has(a[href=\"#still-stuck\"]):has(a[href=\"#in-the-browser\"]) .toc-item[data-depth=\"1\"]{display:none}#table-of-contents:has(a[href=\"#words-you-see-in-floe\"]):has(a[href=\"#technical-terms\"]) .toc-item[data-depth=\"1\"]{display:none}#content-area [data-component-part=\"field-name\"],#content-area [role=\"tablist\"][aria-label=\"Code examples\"]{--primary: 17 17 17;--color-primary: rgb(17 17 17)}"}],"page":{"pagePath":"how-it-works/encryption","slug":"/how-it-works/encryption","pageMetadata":{"title":"How your files are encrypted","sidebarTitle":"Encryption","description":"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.","keywords":["encryption","end to end","dtls","link key","is floe secure","can floe read my files"],"href":"/how-it-works/encryption"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,p:`p`,strong:`strong`,..._provideComponents(),...props.components},{Heading,Warning}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsxs(_components.p,{children:[`Your files are encrypted on your device and decrypted on the other person’s. Nothing in between\ncan read them, and that includes Floe’s own servers. This is what\n`,_jsx(_components.a,{href:`/glossary#encrypted-end-to-end`,children:`encrypted end to end`}),` means. It rests on the introduction: each\ndevice has to get the other’s real ID through Floe’s server. A `,_jsx(_components.a,{href:`/glossary#link-key`,children:`link key`}),` checks\nthat on a link that carries one, and\n`,_jsx(_components.a,{href:`#what-it-does-not-protect-against`,children:`What it does not protect against`}),` says how far that goes.`]}),`\n`,_jsx(_components.p,{children:`There is nothing to switch on. It is not a mode, an upgrade, or a setting. Every transfer works\nthis way, direct or relayed, on floe.one or on an instance you run yourself.`}),`\n`,_jsx(Heading,{level:`2`,id:`three-things-that-follow-from-that`,children:`Three things that follow from that`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The keys exist only on the two devices.`}),` They are generated fresh for each transfer, live in\nthe two browsers or apps involved, and are thrown away when the connection closes. There is no\nkey server, no spare copy of the keys held anywhere, and no recovery: once a transfer is over,\nthat transfer’s keys are gone and cannot be reconstructed by anyone, Floe included.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`The servers handle the introduction, not the content.`}),` The\n`,_jsx(_components.a,{href:`/glossary#signaling-server`,children:`signaling server`}),` passes connection details between the two devices\nfor a few seconds and then plays no further part. It is not on the path the file takes. When a\n`,_jsx(_components.a,{href:`/glossary#relay`,children:`relay`}),` is involved it is on the path, but only ever carrying encrypted packets it\nhas no way to open.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Self-hosting does not change any of this.`}),` The encryption is a property of the connection\nbetween the two devices, not of who runs the server. If you run your own instance you get the same\nguarantee, and the introduction then runs on a server you operate. `,_jsx(_components.a,{href:`/how-it-works/known-limitations#what-the-link-key-cannot-see`,children:`What the link key cannot see`}),`\nsays what that does and does not settle.`]}),`\n`,_jsx(Heading,{level:`2`,id:`what-it-does-not-protect-against`,children:`What it does not protect against`}),`\n`,_jsx(_components.p,{children:`Encryption answers “can anyone in the middle read this”. It does not answer every question, and\nthe honest limits are worth knowing rather than discovering.`}),`\n`,_jsx(_components.p,{children:`The one that matters most is the introduction. Each device sends the other a short ID for its\nencryption key, and those IDs pass through the signaling server. A server that wanted to could\nhand each side an ID of its own instead, sit in the middle, and read everything.`}),`\n`,_jsxs(_components.p,{children:[`A link key is Floe’s check for that. A link from the web app, from `,_jsx(_components.code,{children:`floe`}),` 1.12 and later, or from\nFloe Desktop 1.1 and later carries one after the `,_jsx(_components.code,{children:`#`}),`, and no server receives it. Once the devices\nconnect, each side that holds it proves so, with a proof tied to the certificates actually in use.\nA receiver that holds the link key refuses a sender that cannot prove it, before any file name or\nbyte. A server in the middle does not hold the link key, so it cannot pass.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[`That check does not cover everything, and the server is still part of what you rely on. A\n`,_jsx(_components.a,{href:`/glossary#room-code`,children:`room code`}),` carries no link key, and neither does an older link. The web app’s Send page, `,_jsx(_components.code,{children:`floe send`}),`\n1.12 and later and `,_jsx(_components.strong,{children:`Send`}),` in Floe Desktop 1.1 and later only detect, so a server playing a\nreceiver with no link key gets the whole file. Whoever serves the web app’s JavaScript, and anyone\nwho held the whole link, can pass the check. Where it matters, encrypt the file yourself before\nyou send it.`]})}),`\n`,_jsxs(_components.p,{children:[`Read `,_jsx(_components.a,{href:`/how-it-works/known-limitations`,children:`Known limitations`}),` for that and the\nothers in plain language. A privacy claim is worth more when the exceptions are published\nalongside it.`]}),`\n`,_jsx(Heading,{level:`2`,id:`how-the-encryption-works`,children:`How the encryption works`}),`\n`,_jsx(_components.p,{children:`This section is the technical detail, and you can skip it: nothing in it changes what the sections\nabove say.`}),`\n`,_jsxs(_components.p,{children:[`Floe uses `,_jsx(_components.a,{href:`/glossary#webrtc`,children:`WebRTC`}),` data channels, which run SCTP, the protocol that carries the data, over\n`,_jsx(_components.a,{href:`/glossary#dtls`,children:_jsx(_components.strong,{children:`DTLS`})}),`. DTLS is TLS adapted for separate packets (datagrams): the same cipher\nsuites and the same handshake, over a transport that does not guarantee ordering. This is distinct\nfrom DTLS-SRTP, which is what WebRTC uses for audio and video.`]}),`\n`,_jsxs(_components.p,{children:[`Each `,_jsx(_components.a,{href:`/glossary#peer`,children:`peer`}),` generates a certificate and key pair for the session. The short ID\nfrom the previous section is the certificate fingerprint, a short checksum of that certificate.\nThe fingerprints are carried in the connection-setup messages, the SDP offer and answer, and the\nDTLS handshake verifies the certificate it receives against the fingerprint it was promised. An attacker sitting on the network path cannot substitute a\ncertificate, because they cannot also change the fingerprint that arrived through the signaling\nchannel. An attacker who controls the signaling channel itself can.`]}),`\n`,_jsxs(_components.p,{children:[`A link key is the check on that last case. Once DTLS is up, each side that holds the link key sends\nan HMAC, a hash made with a secret key, over the `,_jsx(_components.a,{href:`/glossary#room`,children:`room`}),` id and the hashes of both\ncertificates DTLS actually used. A server in the middle runs two DTLS connections with certificates\nof its own. A proof from one of them fails on the other, and it cannot make a new one without the\nlink key. The exact frame is under `,_jsx(_components.a,{href:`/reference/transfer-protocol#kc`,children:_jsx(_components.code,{children:`kc`})}),`.`]}),`\n`,_jsx(_components.p,{children:`Keys are short-lived and per-session. They are created when the connection is created and\ndiscarded when it closes.`}),`\n`,_jsxs(_components.p,{children:[`Floe adds no encryption layer of its own on top of this. Integrity in transit comes from DTLS.\nOn top of that, the receiving app checks each finished file against the size the sender\nannounced and, when the sender provides one, against the sender’s `,_jsx(_components.a,{href:`/glossary#sha-256`,children:`SHA-256`}),` of\nthe file. See `,_jsx(_components.a,{href:`/how-it-works/file-checks`,children:`File checks`}),`.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":"system","config":{},"pageMetadata":{"title":"How your files are encrypted","sidebarTitle":"Encryption","description":"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.","keywords":["encryption","end to end","dtls","link key","is floe secure","can floe read my files"],"href":"/how-it-works/encryption"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Three things that follow from that","slug":"three-things-that-follow-from-that","depth":2,"children":[]},{"title":"What it does not protect against","slug":"what-it-does-not-protect-against","depth":2,"children":[]},{"title":"How the encryption works","slug":"how-the-encryption-works","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"floe","siteName":"Floe","title":"How your files are encrypted - Floe","relatedPagesConfig":{"enabled":true,"limit":5,"mode":"automatic"},"navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-03T17:33:09.856Z","gitLastModified":"2026-11-03T17:32:07.000Z","originalFileLocation":"how-it-works/encryption.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Floe\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"How your files are encrypted - Floe\">\u003cmeta data-mint-head property=\"og:description\" content=\"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Floe\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://www.floe.one/docs/how-it-works/encryption\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://floe.one/og.png\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"How your files are encrypted - Floe\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://floe.one/og.png\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/floe/Wb95C_CKui7BohD5/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Floe\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#00A3C9\">\u003clink data-mint-head rel=\"canonical\" href=\"https://www.floe.one/docs/how-it-works/encryption\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/how-it-works/encryption.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://www.floe.one/#organization\",\"name\":\"Floe\",\"url\":\"https://www.floe.one\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/floe/ezxgMLrxNnA-g95b/logo/dark.svg?fit=max\u0026auto=format\u0026n=ezxgMLrxNnA-g95b\u0026q=85\u0026s=8cafdf2bfd539f368800c1e9da5d5bb6\"}},{\"@type\":\"WebSite\",\"@id\":\"https://www.floe.one/docs#website\",\"name\":\"Floe\",\"url\":\"https://www.floe.one/docs\",\"publisher\":{\"@id\":\"https://www.floe.one/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://www.floe.one/docs/how-it-works/encryption#webpage\",\"url\":\"https://www.floe.one/docs/how-it-works/encryption\",\"name\":\"How your files are encrypted\",\"description\":\"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\",\"dateModified\":\"2026-11-03T17:32:07.000Z\",\"isPartOf\":{\"@id\":\"https://www.floe.one/docs#website\"},\"breadcrumb\":{\"@id\":\"https://www.floe.one/docs/how-it-works/encryption#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://www.floe.one/docs/how-it-works/encryption#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"How Floe works\",\"item\":\"https://www.floe.one/docs/how-it-works/signaling\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How your files are encrypted\",\"item\":\"https://www.floe.one/docs/how-it-works/encryption\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://www.floe.one/docs/how-it-works/encryption#article\",\"headline\":\"How your files are encrypted\",\"name\":\"How your files are encrypted\",\"description\":\"Every Floe transfer is encrypted end to end with keys that live only on the two devices. What that protects, what it does not, and how it works.\",\"url\":\"https://www.floe.one/docs/how-it-works/encryption\",\"mainEntityOfPage\":{\"@id\":\"https://www.floe.one/docs/how-it-works/encryption#webpage\"},\"image\":\"https://floe.one/og.png\",\"dateModified\":\"2026-11-03T17:32:07.000Z\",\"keywords\":\"encryption, end to end, dtls, link key, is floe secure, can floe read my files\",\"publisher\":{\"@id\":\"https://www.floe.one/#organization\"},\"isPartOf\":{\"@id\":\"https://www.floe.one/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Floe\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Floe","nav":{"global":null,"groups":[{"group":"Getting started","pages":[{"title":"Send files peer-to-peer with Floe","sidebarTitle":"Introduction","href":"/introduction"},{"title":"Send your first file","sidebarTitle":"Quickstart","href":"/quickstart"},{"title":"Which app should I use?","sidebarTitle":"Which Floe to use","href":"/choosing-floe"}]},{"group":"Web app","pages":[{"title":"Send files from your browser","sidebarTitle":"Sending files","href":"/web-app/sending"},{"title":"Receive files in your browser","sidebarTitle":"Receiving files","href":"/web-app/receiving"},{"title":"Send files through a request link","sidebarTitle":"Sending through a request link","href":"/web-app/request-links"}]},{"group":"Desktop app","pages":[{"title":"Install the desktop app","sidebarTitle":"Installation","href":"/desktop/installation"},{"title":"Send files from the desktop app","sidebarTitle":"Sending files","href":"/desktop/sending"},{"title":"Receive files in the desktop app","sidebarTitle":"Receiving files","href":"/desktop/receiving"},{"title":"Request links: let someone send files to your PC","sidebarTitle":"Request links","href":"/desktop/request-links"},{"title":"Desktop app settings","sidebarTitle":"Settings","href":"/desktop/settings"},{"title":"Keyboard shortcuts","sidebarTitle":"Keyboard shortcuts","href":"/desktop/keyboard-shortcuts"}]},{"group":"CLI","pages":[{"title":"Install the CLI","sidebarTitle":"Installation","href":"/cli/installation"},{"title":"floe send command","sidebarTitle":"floe send","href":"/cli/send"},{"title":"floe receive command","sidebarTitle":"floe receive","href":"/cli/receive"},{"title":"floe version command","sidebarTitle":"floe version","href":"/cli/version"},{"title":"Update the CLI","sidebarTitle":"floe update","href":"/cli/update"},{"title":"CLI flags reference","sidebarTitle":"Flags","href":"/cli/flags"},{"title":"Use a self-hosted server","sidebarTitle":"Self-hosted server","href":"/cli/self-hosted-server"}]},{"group":"Help","pages":[{"title":"Troubleshooting: fixes by error message","sidebarTitle":"Troubleshooting","href":"/troubleshooting"},{"title":"Frequently asked questions","sidebarTitle":"FAQ","href":"/faq"},{"title":"Glossary","sidebarTitle":"Glossary","href":"/glossary"}]},{"group":"How Floe works","pages":[{"title":"How a transfer works","sidebarTitle":"How a transfer works","href":"/how-it-works/signaling"},{"title":"Direct connections","sidebarTitle":"Direct connections","href":"/how-it-works/direct-connection"},{"title":"Relay fallback when a direct connection is impossible","sidebarTitle":"Relay fallback","href":"/how-it-works/relay-connection"},{"title":"File size limits and the 2 GB relay cap","sidebarTitle":"File size limits","description":"Floe sets no size limit on a direct transfer. A relayed one is capped at 2 GB per session. What decides which you get, and how to stay on a direct connection.","href":"/how-it-works/2gb-limit"},{"title":"How your files are encrypted","sidebarTitle":"Encryption","href":"/how-it-works/encryption"},{"title":"How Floe checks that each file arrived intact","sidebarTitle":"File checks","description":"How Floe checks each received file against the size and SHA-256 its sender sent, what the check mark and the Verified row mean, and what they do not prove.","href":"/how-it-works/file-checks"},{"title":"Security and privacy","sidebarTitle":"Security \u0026 privacy","href":"/security-privacy"},{"title":"Known limitations","sidebarTitle":"Known limitations","href":"/how-it-works/known-limitations"}]},{"group":"Self-hosting","pages":[{"title":"Self-hosting overview","sidebarTitle":"Overview","href":"/self-hosting/overview"},{"title":"Docker quickstart","sidebarTitle":"Docker quickstart","href":"/self-hosting/quickstart"},{"title":"Run without Docker","sidebarTitle":"Without Docker","href":"/self-hosting/without-docker"},{"title":"Deploy on Unraid","sidebarTitle":"Unraid","href":"/self-hosting/unraid"},{"title":"Container images","sidebarTitle":"Container images","href":"/self-hosting/images"},{"title":"Configuration reference","sidebarTitle":"Configuration","href":"/self-hosting/configuration"},{"title":"How the client finds the server","sidebarTitle":"Server discovery","href":"/self-hosting/build-time-url"},{"title":"Run behind one domain","sidebarTitle":"Reverse proxy","href":"/self-hosting/reverse-proxy"},{"title":"Add a TURN relay","sidebarTitle":"TURN relay","href":"/self-hosting/turn-relay"},{"title":"Turn on request links","sidebarTitle":"Turn on request links","href":"/self-hosting/request-links"},{"title":"Production deployment","sidebarTitle":"Production","href":"/self-hosting/production"},{"title":"Day-to-day operations","sidebarTitle":"Operations","href":"/self-hosting/operations"}]},{"group":"Reference","pages":[{"title":"Limits and timeouts","sidebarTitle":"Limits","href":"/reference/limits"},{"title":"How the pieces fit together","sidebarTitle":"Architecture","href":"/reference/architecture"},{"title":"Signaling server HTTP API","sidebarTitle":"HTTP API","href":"/reference/http-api"},{"title":"Data-channel transfer protocol","sidebarTitle":"Transfer protocol","href":"/reference/transfer-protocol"},{"title":"Every message Floe can show","sidebarTitle":"Message index","href":"/messages"}]},{"group":"Changelog","pages":[{"title":"Changelog","href":"/changelog"}]}]},"basePath":"","title":"How your files are encrypted - Floe","buildId":"dpl_BSPUBxEoKhhK7HzXVDPxdPvWx4xc","deploymentId":"dpl_BSPUBxEoKhhK7HzXVDPxdPvWx4xc","dynamics":[],"chunks":[]}