diff options
Diffstat (limited to 'docs/meshbay-draft-v5.md')
| -rw-r--r-- | docs/meshbay-draft-v5.md | 71 |
1 files changed, 44 insertions, 27 deletions
diff --git a/docs/meshbay-draft-v5.md b/docs/meshbay-draft-v5.md index ffc30c2..2a0f3b1 100644 --- a/docs/meshbay-draft-v5.md +++ b/docs/meshbay-draft-v5.md @@ -65,7 +65,7 @@ This replaces the informal assurances scattered through v4 §4.2.x and §13. | Client code integrity | ❌ **T3, accepted** | ❌ T3 | ✅ | ✅ | ✅ | | Node content authority | ✅ | ✅ | ✅ sovereign | ✅ | ✅ | | Hub cannot obtain the group key | ✅ | ✅ **since H3 closed** — except in `join_policy = "open"` groups, where it can join legitimately | — | — | ✅ | -| Your identity keys stay yours | ✅ | ✅ | ⚠️ **offline attack on your keypair bundle** — see §7.1. Succeeds against a weak passphrase, and yields your content on *other* nodes plus the ability to sign as you | ✅ | ✅ | +| Your identity keys stay yours | ✅ | ✅ | ⚠️ **offline attack on the bundle they hold** — see §7.1. Succeeds against a weak passphrase, and yields the identity used **on that node only**: nothing on anyone else's | ✅ | ✅ | **The claim this project can make:** *the hub cannot read your content unless it ships you malicious client code.* Since H3 closed (2026-08-14) that is the **only** remaining path, @@ -92,11 +92,11 @@ even the hub."* Three reasons, all deliberate: - **Members and the operator read everything.** Inherent: "end-to-end" here describes *client ↔ node*, never *client ↔ client*. -One boundary deserves naming, because the table above hid it until 2026-08-14: an operator -hosts your content by design, but they should not be able to become *you*. They can try — -your keypair bundle sits on their disk, and a weak passphrase gives it up (§7.1). That is -the difference between a node operator reading what they host and a node operator reading -what other operators host. +One boundary deserves naming: an operator hosts your content by design, but they should not +be able to become *you*. They can still try — a bundle sits on their disk and a weak +passphrase gives it up — but since 2026-08-14 what it gives up is **the identity you use +with them**, which unlocks nothing they did not already have. Reading what they host is by +design; reading what *other* operators host is not, and no longer follows. --- @@ -319,9 +319,15 @@ Hub minimization was considered and **deferred** (decision D4). The hub keeps se the web UI and remains in the trusted path by choice. This section describes what it *does*, not an aspiration. -**Stores:** accounts (username, encrypted email, public keys, status, role), group -registry and membership, IP logs (1 year, legal), node registrations, refresh tokens, -notifications, moderation blocklist. +**Stores:** accounts (username, encrypted email, status, role), group registry and +membership, IP logs (1 year, legal), node registrations, refresh tokens, notifications, +moderation blocklist. + +**No longer stores user identity keys** (2026-08-14). `users.pk_ed25519` and +`users.pk_x25519` are dropped, `PUT /me/keys` is gone, and `/pubkeys` returns an account id +and a node's linking key — nothing to wrap for. Tokens carry no `pk_user` claim either: the +node used to record it as the uploader's identity, which let whoever issued tokens decide +who could delete a file. **Does not store:** file content, file names, private-group indexes, message content, private keys, GEK bundles, keypair bundles, node IPs beyond ephemeral signaling. @@ -371,19 +377,25 @@ separation, on-the-fly encryption. ### 7.1 The keypair bundle, and what it is worth to an attacker (C4) -The bundle carries a user's identity keys, encrypted under their passphrase. It is stored -on **every node whose group they join**, because that is what lets them open their account -from a second browser — the ordinary expectation, and the only mechanism available to a -browser that keeps nothing durable of its own. +A bundle carries **one node's** identity keys, encrypted under the owner's passphrase, and +is stored on that node. It is what lets a second browser open the same account there — the +ordinary expectation, and the only mechanism available to a browser that keeps nothing +durable of its own. + +The adversary is concrete: an operator holding their own node's disk, attacking offline at +their leisure. -So the adversary is concrete: an operator holding their own node's disk, attacking offline -at their leisure. +**What cracking one yields.** The identity that person uses **on that node** — where the +operator already holds the content, the index and every byte they serve. It is not a key +anywhere else: each node gets its own, generated the first time its owner joins it, and a +key one node pinned is a stranger to the next (which asks for a code, like any first +contact). Until 2026-08-14 a single identity was copied to every node joined, so one crack +yielded content on *other* operators' nodes and the ability to sign as that user anywhere — +that was the part worth attacking, and it is gone. -**What cracking one yields.** The user's identity keys — and with them, content on -**other** nodes and the ability to sign as that user. *Not* the content on the attacking -operator's own node, which they host in the clear by design. This is the one place where a -node operator can reach past the boundary the rest of the design gives them, and v5 did not -say so before 2026-08-14. +Two smaller consequences fall out. Two operators can no longer tell they host the same +person by comparing keys. And the hub publishes no user keys at all now (§6.1), so there is +no directory left to substitute from. **Why Argon2id.** PBKDF2 is compute-only, which is exactly what a GPU is good at. Measured on the development machine: PBKDF2-SHA512 600k costs 241 ms per guess on one core, @@ -417,8 +429,10 @@ anything about one. lives in IndexedDB for the session. - The pre-proof window that serves bundles is still bounded (4 fetches) and audited. -C4 closes properly when the native client stops storing bundles remotely (Phase 13.3): -the material belongs on the user's own device, not on the hub *or* on other people's nodes. +C4 is **reduced, not closed**: bundles still sit on disks their owner does not control, and +a weak passphrase still gives up the key for that node. It closes when the native client +stops storing them remotely (Phase 13.3) — the material belongs on the user's own device, +not on the hub *or* on other people's nodes. --- @@ -435,11 +449,14 @@ the material belongs on the user's own device, not on the hub *or* on other peop | Transport | WebRTC | WebRTC **+ QUIC** | | Positioning | **Convenience tier** — zero install | Recommended for sensitive use | -**Several browsers, one identity.** A browser keeps nothing durable the user controls, so -the account's keys are backed up — encrypted under the passphrase — to the nodes whose -groups it joins. Any other browser then recovers them with the passphrase alone: same -identity, same pin, no second pairing code. This is what makes the product behave the way -people expect, and it is also finding C4 (§7.1). The native client removes the need for it +**Several browsers, one identity per node.** A browser keeps nothing durable the user +controls, so the identity it creates for a node is left with that node, encrypted under the +passphrase. Any other browser recovers it there with the passphrase alone: same identity on +that node, same pin, no second code. Joining a *different* node creates a different key and +needs that operator's code, which is the first contact it has always needed. + +This is what makes the product behave the way people expect, and it is also finding C4 +(§7.1) — with a blast radius of one node. The native client removes the need for it entirely, which is a large part of why it exists. The SPA is not deprecated. It is the zero-install path and it stays. It must be labelled |