Updated 16 October 2026

How HushOS protects your files.

What happens to a file from the moment you add it, in plain words. Each step keeps the exact terms underneath for anyone who wants to check them against the code. Where this page and the code disagree, the code is right and this page has a bug.

On this page

1Your password never leaves your device

Never reaches us
Your password, and this device’s own key
What reaches us
A proof that you know it, a record that can check that proof, and a name for this device

When you sign in, your device proves it knows your password without sending it, not even in a scrambled form. For your password, we keep only a record that can check that proof. Guessing your password from that record means trying passwords one at a time, and each try is slowed down on purpose. Signing in with an email that has no account gets the same kind of answer, so the sign-in page doesn’t reveal who has one.

Once you’re in, your browser holds a session that ends after 7 days unused, or after 30 days at most.

Each session belongs to a device. Your devices, in Account, lists every browser and phone signed in to your account. Removing one asks for your password and signs it out at once. The next time that device checks in, it learns it was removed and clears what it kept for your account; we can’t promise that, because a device kept offline never checks in. When a device we haven’t seen before signs in with your password, we email you.

The exact terms
Protocol
OPAQUE (Ristretto), Serenity implementation
Hardening
Argon2id, 65,536 KiB memory, 3 iterations, parallelism 4
Server stores
The OPAQUE registration record
Client receives
An export key that only the client ever sees
Unknown email
Answered with a decoy record so lookups do not reveal accounts

OPAQUE produces two secrets. The session key is shared with the server; HushOS uses a separate random token for its application sessions. The export key is known only to the client. Only the export key is used to wrap the account key, and only after a further derivation step.

Sessions and transport

Verification links
32 random bytes, sent in a URL fragment, stored only as SHA-256, valid 30 minutes
Login attempts
Random handles, stored hashed, consumed after 5 minutes or one finish
Sessions
7 days idle, 30 days at most, 32-byte token, only its SHA-256 stored
Devices
Each session belongs to one device. A device keeps its own Ed25519 key and signs back in to its own entry with it; anything else signs in as a new device
Removing a device
Needs your password, through a one-use OPAQUE exchange bound to your session; ends its sessions at once. For a week, the device is told it was removed when it checks in
New-device email
Sent when a new device signs in with your password; it never names the device
Cookies
HttpOnly, SameSite=Lax, Secure with the __Host- prefix under HTTPS
Mutations
Exact Origin check, JSON only, 16 KiB body limit, per-address rate limits
Responses
private, no-store and no-referrer

2Your keys are made on your device

Never reaches us
Your account key, unlocked
What reaches us
Copies of it, locked by your password and by your recovery phrase

When you sign up, your device makes the key for your account. Your password locks one copy of it and your recovery phrase locks another. Changing your password locks the same key again, so nothing else has to change.

Your device also makes your identity keys, which are what other people lock things to when they share with you, and a key for your workspace. Every folder and file hangs off the workspace key, each with a key of its own.

The exact terms

Your account key, also called the master key, is 32 random bytes generated in your browser. It is not derived from your password. Two independent wrappings of the same key exist:

Password wrap
HKDF-SHA-256 over the OPAQUE export key, then XChaCha20-Poly1305
Recovery wrap
HKDF-SHA-256 over the recovery secret, then XChaCha20-Poly1305
Salt and nonce
Fresh 32-byte salt and 24-byte nonce on every wrap
Bound to
Your account ID, root revision, and credential or recovery revision

Every envelope carries associated data that names its purpose, version, and owner. An envelope moved to another account or another version fails to open.

At signup the browser also generates your identity: an X25519 key pair for encryption, an ML-KEM-768 key pair (the post-quantum key exchange NIST standardised as FIPS 203), and two signing key pairs, Ed25519 and ML-DSA-65 (the post-quantum signature standardised as FIPS 204). The private halves are wrapped with keys derived from the account key. Your identity signs a statement over all four public keys and your account ID with both signing keys; the server refuses an identity whose statement does not verify, and every device checks it again. Only public keys and wrapped private material reach the server. The X25519 and ML-KEM keys together are what a share is sealed to, and what a report’s key is sealed to.

Identity keys

Encryption
X25519, libsodium
Post-quantum
ML-KEM-768 (FIPS 203), expanded from a 64-byte seed wrapped under the account key
Signatures
Ed25519 and ML-DSA-65 (FIPS 204), each from a 32-byte seed wrapped under the account key. A signature is both, 3373 bytes, and holds only if both halves verify
Keys statement
All four public keys, the key version and your account ID, signed with both keys; checked by the server on every upload and by every device that reads it
Version
2. An identity made before ML-DSA keeps its keys and gains one at its next unlock

The twelve words two people compare are version 3: a digest of the X25519 and Ed25519 keys and of the ML-DSA and ML-KEM keys, so comparing words checks all four.

Every workspace has its own 32-byte key, generated in your browser. It is random, not derived from your account key, so it can be granted to another person later without giving them anything of yours. What you hold is a grant: the workspace key wrapped under a key derived from your account key.

Workspace key

Workspace key
32 random bytes, created on your device when the workspace is
Grant wrap
HKDF-SHA-256 over the account key, then XChaCha20-Poly1305
Bound to
Your account ID, the workspace ID, your root revision, and the workspace key revision
Server stores
One grant per member per workspace, never the key

Folder and file keys hang off the workspace key, not off your account key. That is what keeps rotation cheap: replacing your account key rewraps one grant per workspace you belong to, and nothing beneath it moves.

In your browser

Account key
Held in plaintext only inside a Web Worker, never in application state
Remembered unlock
The worker wraps the account key with a non-exportable AES-256-GCM device key held in IndexedDB; locking or signing out clears it across tabs in that browser
Device key
A non-exportable Ed25519 key in its own IndexedDB database, which signs this browser back in to its own entry in Your devices. Kept when you lock, with your account ID beside it in the clear, since it is read before you unlock; deleted when you sign out or the browser is removed
Tree mirror
Your tree as the server holds it, ciphertext only, kept in IndexedDB so search and folder listings run on the device; cleared when you leave the workspace. Its IDs, sizes and times are as readable as they are to the server
Rollback marks
The highest settings and identity versions this browser has seen, so an older copy from the server is refused. Sealed with XChaCha20-Poly1305 under a key derived from your settings key, which a new account key keeps, so a locked browser holds ciphertext; a mark that does not open stops the check rather than count as none
Signing out
Deletes everything this browser kept for the account, databases included rather than emptied: the remembered unlock, the device key, the rollback marks, the tree mirror, the upload journal and stash, family records, a saved return to a link, and the email address a sign-up link went to. Only display settings stay: theme, contrast, sounds, list or grid, and sort order

How remembered unlock and the account key rotations work, step by step, is in the accounts and keys design document.

3Your recovery phrase gets you back in

Never reaches us
Your 24 words, readable
What reaches us
Your account key locked by the words, the words locked by your account key, and a public key that checks them

The 24 words you save at sign-up lock their own copy of your account key. With the phrase and a link we email you, you can set a new password and your files stay as they were. Email alone can never get you back in. Resetting your password this way gives you a new phrase and signs you out everywhere else.

In Account you can also change your password, make a new recovery phrase, or rotate your account key. Each one asks for your current password and signs you out of your other browsers. You can also replace your sharing keys, which the people you share with follow without comparing words again (see sharing below).

The exact terms
Phrase
A 32-byte secret made on your device, shown as 24 English BIP39 words
Backup
The secret is also stored encrypted by the account key, so the phrase can be shown again while your device is unlocked
Reset needs
A verified email link and a signature from a key derived from the phrase
After a reset
The unchanged account key is rewrapped, every session is revoked, a new phrase is issued, and you are signed in with the new password

During a reset the browser re-registers with OPAQUE under the new password and rewraps the unchanged account key. The server checks the signature and every binding and replaces the credentials in one transaction.

In Account

Change password
Rewraps the same master key; preserves the recovery phrase and identity keys
Make a new phrase
Creates new 24-word recovery credentials; preserves the password, master key, and identity keys
Rotate account key
Generates a new master key and recovery phrase; rewraps the identity keys (current and earlier), the settings key and every workspace grant, and preserves the password
Replace sharing keys
Generates new identity keys at the next key version, vouched for by a signature from the current signing key; keeps the earlier ones, still wrapped under the master key, to open what was sealed to them; seals every share again under the new keys

Each action needs your current password through a fresh OPAQUE exchange, revokes existing sessions and pending recovery attempts, and rejects stale concurrent changes. After either rotation, save and confirm the new recovery phrase before continuing into the app. The full sequence is in the accounts and keys design document.

4Your files are locked before they’re sent

Never reaches us
Names, contents and thumbnails, readable
What reaches us
Locked, padded pieces, sent straight to storage

Your device locks each file, and its name, type and modified time, before any of it leaves. Each file is padded before it is locked, so from a locked copy our servers learn only roughly how large the file is, to within a few percent. The locked pieces go straight from your device to storage; our app server never handles them. Thumbnails are made on your device and locked inside the file itself. Downloads come back the same way and are unlocked on your device, and previews fetch only the parts they need.

Padded to
5.00 MB
Looks the same to us as
Any file from 4.88 MB to 5.00 MB
The app’s own padding rule, for a file without a thumbnail; a thumbnail is padded with it. Drag to try a size.
The exact terms

Every folder and file in Drive has its own key, wrapped under its parent’s key; the root folder’s key is wrapped under the workspace key. A file’s key locks its details and wraps a separate content key for each version of the file. The server holds a tree of ids and envelopes.

Folder and file keys

Node key
32 random bytes per folder or file, wrapped under the parent node key
Metadata
Name, type, size and modified time, encrypted under the node key and padded to 256-byte steps, so its length does not follow the name
Content key
32 random bytes per file version, wrapped under the node key
Wrap
XChaCha20-Poly1305 with a fresh 24-byte nonce
Bound to
The workspace, the node, its parent and the parent key epoch, or the version and object

An envelope moved to another folder, another version or another workspace fails to open. A key epoch counts each time a node’s key changes; it is what lets a rotation tell old envelopes from new ones.

Uploads and downloads

Cipher
XChaCha20-Poly1305, one 16-byte tag per 8 MiB chunk
Chunk nonces
Derived from a 16-byte per-object nonce and the chunk index
Transfer
Browser to object store directly, by signed URLs valid 15 minutes for shared content, an hour otherwise
Resume
A journal on your device records each chunk’s digest before it is sent. Until the upload finishes it also holds the file’s name and size in the clear, even while locked; signing out deletes it
Thumbnails
Rendered on the uploader’s device and sealed into the file’s own encrypted object, under a key derived from the content key; the server cannot tell which files have one
Size
The server records the size the store confirms for the encrypted object, which is padded (below); the file’s exact size is sealed in its envelope

File contents are padded before they are encrypted. Below 256 bytes, everything is 256 bytes. Above that, at most 6.25% is added, so the server learns a file’s size only to within roughly 2 KiB around 50 KB, 32 KiB around 1 MB, 2 MiB around 100 MB and 32 MiB around 1 GB.

Every name and every version is also signed by the account that wrote it. Your device checks each signature against your own keys and your contacts’ pinned keys. What a contact wrote shows as theirs; if you never compared words with them, Info says Not verified beside their name, with no mark on the item. Anything your device can’t tie to you or a contact is marked Unverified. It names the writer only from your own contacts: you, a contact, or someone it can’t tell; the server tells it nothing more than an account id. Keys someone has replaced no longer vouch for what they signed. If your device can’t run the check at all, because your contacts or your own earlier keys didn’t load, every item shows Couldn’t check until it can, never no mark. A key that only opens a folder, such as a link’s, can no longer plant a file or rename one unnoticed. Unverified items still open: it is a warning, not a lock.

Padding and signatures

Padding
The file and its thumbnail are padded together to a Padmé bucket: 256 bytes at least, then at most 6.25% more up to 64 KiB, 3.125% up to 4 GiB, 1.5625% beyond. Padding is under the content key and counts towards storage
Fetching
Downloads and whole-file previews fetch the padding too, and so does any read that reaches a file’s last chunk, such as seeking to the end of a video, so the store does not see where the file ends
Viewers
After you unlock, the app fetches every viewer, syntax grammar and thumbnail renderer once, so which ones it fetched does not say what you opened
Signatures
Ed25519 by the writer’s identity key over the workspace, item, kind, metadata version and SHA-256 of the metadata envelope; and over the item, version, object, content suite and SHA-256 of the content-key envelope
Re-sealed
A rotation, a copy or a rename re-signs what it locks again. Only a record that verified is signed as the writer’s own; anything else gets a re-sealed statement that says it was re-locked, not vouched for, and stays Unverified
Checked
By the server against the writer’s current key before it stores a change, and again on your device against keys you trust; a check that cannot run shows as Couldn’t check
Writer
Stored and served as an account id alone; your device names it from your contacts. Link visitors get no signatures and no writer
Not signed
Moves, trash and restore, which change no envelope; tags

Independent chunks are what make ranged previews and resumed uploads plain arithmetic. A chunk is never re-encrypted under the same key and nonce with different bytes: a resumed upload proves the file is the same one, chunk digest by chunk digest, or starts over with fresh material.

5Sharing gives one person their own key

Never reaches us
The item’s key, unlocked
What reaches us
A copy of that key, locked for one person’s devices

Sharing a folder or file with another HushOS account locks a copy of its key for that one person, on your device, so only their devices can open it. The lock uses two methods together, one of them designed to resist future quantum computers, so a copy of our database taken today stays shut even if the older method is broken later.

Every share is locked with a fresh key made for it alone and signed by the person sharing, so a key stolen later doesn’t open what was shared before, and nobody else can pass a share off as theirs.

We hand out the keys people share to, so HushOS lets you check them. When you add someone, or something they shared shows up for you, their keys are remembered the first time your device sees them, and you can share with them at once. If you remove someone, what they share afterwards waits until you open it yourself. Comparing twelve words, at any time, confirms the keys are really theirs: Check it’s them in Contacts. If they replace their sharing keys in HushOS, the change is signed by their old keys, and your device checks that signature and follows it when you next share with them, open something of theirs or check them. It never follows in the background, so the server can’t learn whom you’ve added by watching what your device looks up. Any other change is shown to you, and nothing is shared with or sealed again to the new keys, and nothing that person shared opens (what they shared before included), until you continue or check it’s them. Links never pause.

The exact terms

The seal is hybrid: an X25519 agreement between a fresh key made for this share and their identity key, and an ML-KEM-768 encapsulation to their post-quantum key, combined into one key that seals the node key. Opening it needs both private halves. Your identity signs the result with both its signing keys, Ed25519 and ML-DSA-65, and their device checks both against the keys it pinned for you before opening anything. The recipient mounts the shared item as a root of its own under “Shared with me”.

Seal
X25519 agreement from a per-share ephemeral key plus ML-KEM-768 encapsulation, HKDF-SHA-256 over both secrets, then XChaCha20-Poly1305 over the node key
Envelope
Suite 4, 4565 bytes: the ephemeral key, the 1088-byte ML-KEM ciphertext, nonce, the sealed node key, and the sharer’s 3373-byte Ed25519 and ML-DSA-65 signature
Older suites
Suites 1 to 3 are refused: not accepted, not served, not opened
Replacing keys
A new identity at the next key version, signed with both keys of the one it replaces; a contact’s device asks for the whole chain and checks it from the keys it pinned, only when the person shares with them, opens something of theirs or checks them. Replaced keys vouch for nothing: what they signed reads as signed with earlier keys, never verified, and a share they signed waits to be shared again
Whose key
A contact you pinned: version 3, holding their X25519 and Ed25519 keys and the digests of their ML-DSA and ML-KEM keys. First-seen when your device remembered the keys it was given (adding them, or opening something they shared); verified once you both compared their twelve words, in person or on a call
Roles
Viewer, or editor; an editor’s uploads land in your storage
Authorization
Checked on every request by walking up the tree to the nearest live share
Server holds
The sealed box, the role, and who shared with whom

Because the server serves public keys, a dishonest server could substitute one of its own. That is why contacts are pinned: a person’s keys are recorded in your encrypted settings the first time your device sees them, when you add them or something they shared first shows up, and that first-seen pin is what everything you share with them is sealed to. This is trust on first use, as in Signal and WhatsApp, and it has a cost: for someone you never compared words with, whoever runs the server could hand your device its own keys as theirs at that first moment, and then read what you share with them and make shares and changes that look like theirs. Comparing twelve words, which cover all four keys, confirms the pin is theirs and marks it verified; a mismatch is the time to remove them from your contacts and stop sharing each item with them, which ends that share and changes the keys of what it covered. After the first moment, a change is never used silently: a served key that does not match the pin, with no chain signed by the pinned keys, pauses everything with that person, sharing and opening alike, until you continue or check. Each browser also keeps its own record of the keys it has acted on for each person, outside the settings, so a newer copy of your settings that drops or swaps a pin is met as a change rather than as someone new. That record is sealed under a key that exists only while your account is unlocked, and signing out deletes it; after you sign back in, that browser trusts the contacts in your settings, as a new device does. A pin made before post-quantum identities becomes first-seen once its person’s new keys are signed by the key it held. Shares are only ever sealed hybrid: a person without a post-quantum key yet is not shared with until they have one. Every path that seals to a contact goes through the pin, and the re-keying that follows a revocation seals only to the shares and links your own encrypted record says you made, whatever the server lists. Your device also remembers the newest version of your settings it has seen, and the newest version of your own sharing keys it has opened, and refuses an older copy of either, so the server cannot bring back a key you replaced. A new browser has nothing to compare against yet.

7Stopping a share really stops it

Never reaches us
The item’s new keys, unlocked
What reaches us
The new keys, locked again for everyone who still has access

When you stop a share or turn off a link, that person is refused on their next request. Then your device changes the keys for that folder and everything in it, and locks them again for everyone who still has access. Nothing the removed person kept opens anything new.

The exact terms
Refused
On the next request, on every route
Keys
The shared item and everything beneath it get fresh keys under a new epoch; the old keys are gone
Re-sealed
Every remaining share and link, under the new keys, to the pinned keys of each remaining person
Content
Not re-encrypted; the guarantee is about keys and authorization
Download links
Already issued ones expire within 15 minutes

How a rotation visits every item, survives moves made while it runs, and keeps older envelopes apart is in the Drive design document.

8Anything shared can be reported

Never reaches us
What is in anything nobody reported
What reaches us
A reported item’s key, locked to the people who run the service; a folder’s key opens what is in it

Anyone who can see something through a share or a link can report it. Reporting is the only way the people who run the service can see a file: the reporter’s device locks that one item’s key to them. They can then dismiss the report, remove the content, hold it, suspend the uploader, or pass it to the relevant authority. Nothing you haven’t shared can be reported, because nobody else can see it.

The exact terms
Who can report
Anyone with access through a share or a link
What is sealed
The reported item’s key, sealed on the reporter’s device to each operator’s X25519 and ML-KEM-768 keys together when the operator has an ML-KEM key; otherwise, to their X25519 key alone, until they next sign in. The operators and their keys come from the server
What is kept
A snapshot of the reported tree and a hold on its stored bytes, past the owner’s deletion
Evidence
Optionally copied to a separate write-once bucket the application cannot delete from
Not kept
Uploader network addresses; the service does not log them

An operator opens a report under their own identity. Which operators a report is sealed to, and their keys, come from the server, so whoever runs the server can open what is reported to it.

What the server can see

Seen by
Name
Locked, unreadable to us
Folder
Item 0192f3a1-… inside 0192f2c7-…
Size
About 1.22 MB, padded
Contents
Locked pieces in storage
Changed
Locked; we see a save on 14 Sept, 09:14, by your account
One sample file. The ids are made up; the rest follows the table below.
Never
File names, contents, thumbnails, folder names, or any key
Always
Your email, the shape of your tree (ids and parents), the size of each encrypted object (padded, so a file’s size only to within a few percent), times, how much you store, and which account wrote each change
Sharing
Which accounts you share with, and that a link exists; not what is behind it
Search
Nothing. Search runs on your device over names it has already decrypted; no query is sent anywhere.
Tags
That a sealed tag list exists, its size in coarse steps, and when it was last saved; not a name, which items carry a tag, or how many. Tags are never written on an item, so someone you share with sees none of them.
Reports
The content of an item, once someone with access reports it
Devices
The name each of your devices gave itself or you gave it (names are not encrypted), its kind, how it signed in, and when it was added and last active, to the hour
Later, with a quantum computer
Shares and reports are sealed with X25519 and ML-KEM-768 together, so opening one still needs the ML-KEM private key even if X25519 is broken, and the signatures that decide whose keys to trust (identities, their replacements, shares) need ML-DSA-65 too. Reports filed before reports became hybrid, and reports to an operator who has no ML-KEM key yet, are sealed under X25519 alone, and file and folder signatures are still Ed25519 alone.

Families, on servers that offer them: HushOS’s server knows the family’s name, who is in it and what each person can do, who invited and let in whom, the email addresses invitations went to, and how many family folders there are with their sizes, padded as every file’s is. It can’t open family folders.

Joining a family takes no words. When a manager lets someone in, the manager’s device writes the keys HushOS gives it for them into the family’s member list, and the newcomer’s device takes the family as HushOS first shows it, then holds on to it: from then on, a different member list, an older one, or another family key is noticed and the family is paused there, never used. Until two members check each other, whoever runs the server could hand a manager keys of its own for a newcomer, or show a newcomer a family it made up, and read what goes into those family folders. Checking takes twelve words, any time, from Check it’s them beside their name on the family page: when the words match, both devices see the same family and each has the other’s real keys; when they don’t, nothing is saved. A check is best made with the person who made the family. Nobody is given the role of managing the family, or of organizer, until whoever gives it has checked it’s them, since managers can let people in and change the family.

Where it runs

HushOS is open source, and anyone can run their own copy. Who runs the copy you use decides where it runs.

hushos.com
Run by HushOS, a company incorporated in Delaware, United States, with its servers and storage in the European Union
A self-hosted copy
Run by whoever set it up, on their own servers, under their own terms

Either way, your browser sends locked files straight to the object store, and the app server never handles file bytes. Every page is served with a content security policy that limits which scripts run and where the page can connect, and with the usual protective headers.

The exact terms

Every page carries a Content Security Policy: scripts run only from the app’s own origin, under a per-request nonce, with WebAssembly allowed and eval not. The page may connect only to itself and to the object store. Every response carries X-Content-Type-Options, X-Frame-Options: DENY, a referrer policy, a cross-origin opener policy, a permissions policy that switches off camera, microphone, location and payment, and, over HTTPS, HSTS for a year.

What this can’t do

  • If you lose your password, your recovery phrase and every browser that remembers you, your files are gone. Nobody can get them back, including us.
  • Someone who downloaded a file while they had access keeps that copy. Stopping a share protects what comes next; it can’t reach into someone else’s device.
  • Signing out other browsers, or removing a device, takes effect when they next check in with the server. It can’t erase keys or files a device already holds offline.
  • Replacing your recovery phrase stops the old one from resetting your password. A recovery kit you downloaded earlier still holds the old phrase and your account key as it was then, so it can still open that key offline. Password resets and a new recovery phrase keep the same account key; only replacing the account key makes a different one.
  • Replacing your account key can’t erase old locked copies, or take back private identity keys someone already pulled out of an older key bundle.
  • The server sees what’s listed above: your email, padded sizes, times, who wrote each change and how your folders nest. Padding hides a file’s exact size, not roughly how big it is.
  • For people you never compared words with, whoever runs the server could put its own keys in front of theirs the first time your device sees them, and then read what you share with them. Comparing twelve words, at any time, rules that out from then on.
  • In a family nobody checked, whoever runs the server could plant its own keys for a newcomer, or show a newcomer a family it made up, and read what goes into those family folders. Two members checking each other rules that out from then on, not for what was added before.
  • Items written before HushOS signed changes, and anything re-locked without a signature your device could verify, show as Unverified until someone writes them again.
  • Whoever runs the server chooses which operator keys a report is sealed to, so they can open anything reported to them.
  • Replacing sharing keys with stolen keys would look like a real replacement to the people you share with, and their devices follow it. Comparing twelve words again, from Check it’s them, shows the new keys’ words.
  • Signatures say who wrote an item, not that it is the newest version: the server could still serve an older, signed state of it. A report to an operator without a post-quantum key, and any report filed before reports became hybrid, is sealed under X25519 alone.

Check it yourself

The byte-level protocols live in the @hushos/crypto package and are specified in two design documents beside it: one for accounts and keys, including key rotation and remembered browser unlock, and one for Drive, including folder keys, uploads, sharing and rotation. The rest of the suite will be built on the same keys and rules, and documented here in the same detail when it ships.

Read the code on GitHub