Skip to content

Accounts and the vault

Your password is turned into two different things

When you type your master password, your browser scrambles it slowly on purpose (about a second). That slowness makes guessing passwords very expensive for anyone who tries.

From the scrambled result, the browser makes two separate things:

                      your master password
                              |
               slow scramble (on your device)
                              |
              +---------------+---------------+
              |                               |
        LOGIN PROOF                     PASSWORD KEY
     sent to us, so we can            never leaves your
     check it's really you            browser; unlocks
     (we keep only a scrambled         your vault
      copy of it)

The two can't be turned into each other. Knowing the proof doesn't reveal the key.

Your vault: a locked box we store for you

Your vault holds what makes roamd work anywhere: your browser key (what your computers recognise), the identities of your computers (so impostors are spotted) and your Voice settings.

 +-------------------------- your vault --------------------------+
 |  browser key         computer identities       voice settings  |
 +------------------------------+---------------------------------+
                                |
                 locked with the VAULT KEY (random)
                                |
            +-------------------+-------------------+
            |                                       |
 vault key locked with                 vault key locked with
 your PASSWORD KEY                     your RECOVERY KEY
 (normal use)                          (if you forget the password)

We store all of this, but locked. Without your password or your recovery key, it's unreadable, to us as well.

Logging in on a new browser

 new browser                                     our website
 -----------                                     -----------
 you type email + password
 "what's the salt for this email?"  -------->
                                    <--------   salt + settings
 slow scramble -> proof + password key
 send proof                          -------->   check proof
                                    <--------   your locked vault key
 unlock it with the password key
 download + unlock your vault        <--------   locked vault items

If you forget your password

Your recovery key unlocks the second copy of the vault key, and you choose a new password. Everything is still there. Lose both and the vault is gone for good. We have no master key.

Other protections

  • Guessing is limited: a handful of tries per minute per email, however many computers the guesser uses.
  • Nobody can find out who has an account: asking about an email that isn't registered gets an answer that looks just like a real one.
  • Changing your password logs out your other browsers.
  • The page locks itself after 15 minutes without use, or when you close the tab.

Key derivation

 master password + per-account random salt
        |
        v
 Argon2id (memory-hard; OWASP-recommended settings or stronger)
        |
        +-- HKDF-SHA256 -> login proof   (sent to the hub)
        +-- HKDF-SHA256 -> password key  (never leaves the browser)
  • The two outputs use separate HKDF labels, so the proof reveals nothing about the key.
  • The browser enforces a minimum Argon2 strength, so a hostile hub can't weaken the hashing to make a captured proof cheap to crack.
  • The hub stores only a hash of the proof and compares in constant time. Offline guessing against a leaked database costs a full Argon2id run per guess.

Vault structure

 vault key: 256-bit random, generated in the browser
   |
   +-- sealed under the password key  -> stored on the hub
   +-- sealed under the recovery key  -> stored on the hub
   +-- seals each item with XChaCha20-Poly1305
         (bound to the item's name and revision)
  • Items: the browser's SSH key (Ed25519), the pinned identities of your machines, and Voice settings (per-machine on/off, keywords, threshold).
  • Binding each item to its name and revision means the hub can't swap items or pass off an old version as new.
  • Sync: browsers fetch changes since their last sync. Writes must name the next revision; on a conflict the browser re-applies its change on top of the latest version.
  • Per-item and per-account size limits apply.

Recovery key

160 random bits plus a checksum (to catch typos), shown as 9 groups of 4 characters. Like the password, it yields a separate key and proof; the hub keeps only a hash of the proof.

 recovery key -> proof checked by hub -> hub returns vault key sealed
                                         under the recovery key
 browser: unlock vault key, choose new password, re-seal
 hub: replace password material, end every session

Account protections

Protection Behaviour
Guessing limits Per visitor and per email, so spreading guesses across many addresses doesn't help
Account privacy Unknown emails get responses shaped like real ones, so you can't probe who has an account
Password change Requires the current password; ends other sessions
Recovery Ends all sessions

Sessions: a random 256-bit token in an HttpOnly; Secure; SameSite cookie; the hub stores only its hash. The unlocked vault key lives in the tab only, and is cleared on tab close, logout or idle lock.

Web hardening

Every response carries a strict Content-Security-Policy: no inline or third-party script, connections only to this site, no framing, plus nosniff and no-referrer. The browser test suite fails on any policy violation.