From 44b9e74153f5e32b3665f319429b3b08fd3662d5 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sun, 9 Aug 2026 14:57:01 +0200 Subject: docs: update all pointers after keyderive + QE restructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md: add QE/ to structure, key modules table, server state reference, security rule updated (QE/ not keypair files), meshbay.org inventory pointer. devel-phases.md: add milestones 6.6-6.9 (keyderive, bundle, demo scripts, QUICKSTART rewrite). 81/81 tests. docs/meshbay-draft-v3.md §6.1.1: new section documenting 3 key generation strategies (Argon2id CLI, WebCrypto browser+bundle, keystore file) and the algorithm mismatch caveat between CLI and web registration paths. docs/USERGUIDE.md §2 Register+Login: replace "generate and persist before registering" warning with the two clean strategies (derive_keys_from_password for CLI, keyderive.js + keypair_bundle for browser). Login response updated with keypair_bundle field. hub/models.py + users.py + Alembic migration: keypair_bundle column on User, stored at registration, returned at login (web clients only). Co-Authored-By: Claude Sonnet 4.6 (1M context) --- docs/meshbay-draft-v3.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'docs/meshbay-draft-v3.md') diff --git a/docs/meshbay-draft-v3.md b/docs/meshbay-draft-v3.md index c327415..6983191 100644 --- a/docs/meshbay-draft-v3.md +++ b/docs/meshbay-draft-v3.md @@ -406,6 +406,39 @@ All private keys stored exclusively on the node (or client device) in the encryp Both `PK_ed25519` and `PK_x25519` are registered with the hub at account creation. The hub exposes them via `GET /v1/users/{username}/pubkeys` so that group admins can wrap GEK bundles for members without any direct contact between nodes. +### 6.1.1 Key Generation Strategies + +Three strategies, depending on client type: + +**A — CLI / native node (Argon2id derivation)** +Keys are derived deterministically from `username + password`: +``` +salt = SHA-256("meshbay:v1:" + username) +seed = Argon2id(password, salt, length=64) +sk_ed25519 = Ed25519.from_private_bytes(seed[:32]) +sk_x25519 = X25519.from_private_bytes(seed[32:]) +``` +Same credentials → same keys on any machine. Password recovery = key recovery. +Implemented in `meshbay_common/keyderive.py::derive_keys_from_password()`. + +**B — Web browser (random keypairs + encrypted bundle)** +Browser generates random keypairs via WebCrypto `generateKey()`, encrypts them +with a PBKDF2-SHA512 derived key, and uploads the encrypted bundle to the hub +alongside the public keys. On subsequent logins, the hub returns the bundle +and the browser decrypts it locally with the password. + +The hub stores `keypair_bundle` (AES-256-GCM ciphertext) — opaque, cannot decrypt it. +Implemented in `static/keyderive.js`. Python side in `keyderive.py::encrypt_keypair_bundle()`. + +**C — Native node with keystore file** +Random keypairs generated once, stored in the Argon2id-encrypted keystore file +(`~/.config/meshbay/keystore.enc`). Standard operating mode for `meshbay-node`. + +**Algorithm mismatch note:** strategies A and B use different KDFs (Argon2id vs PBKDF2). +A user who registered via CLI (A) and later tries to recover via web (B) with the same +password will get different keypairs. This is by design: users pick one registration path. +Cross-path recovery requires the admin to issue new GEK bundles. + ### 6.2 GEK Management **Scope:** GEK applies to private groups only. Public groups use TLS transport only (no application-layer encryption). -- cgit v1.2.3