aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/USERGUIDE.md39
-rw-r--r--docs/meshbay-draft-v3.md33
2 files changed, 64 insertions, 8 deletions
diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md
index b49eb73..af03a60 100644
--- a/docs/USERGUIDE.md
+++ b/docs/USERGUIDE.md
@@ -62,9 +62,26 @@ MeshBay has three components. Understanding which role each plays avoids a lot o
### Register
-Registration requires submitting your Ed25519 (signing) and X25519 (key agreement) public keys at account creation time. These are used by other members' nodes to wrap GEK bundles for you, and by nodes to verify your JWT offline.
+Registration submits your Ed25519 (signing) and X25519 (key agreement) public keys. These let other members wrap GEK bundles for you and let nodes verify your JWT offline.
-**Critical:** generate and persist your keypairs before registering. If you regenerate them later, all GEK bundles stored for you on the hub become undecryptable. See the Quickstart for the key generation script.
+**Deux modes de génération de clés :**
+
+**Mode CLI / native node** (`setup_demo.py`, `meshbay-node`) :
+Les clés sont *dérivées* de votre username + password via Argon2id — pas besoin de
+fichier de clés séparé. Même identifiants → mêmes clés sur n'importe quelle machine.
+Implémenté dans `meshbay_common.keyderive.derive_keys_from_password()`.
+
+```python
+from meshbay_common.keyderive import derive_keys_from_password
+sk_ed, sk_x = derive_keys_from_password("alice", "MonMotDePasse!")
+```
+
+**Mode navigateur** (interface web) :
+Le navigateur génère des clés aléatoires via WebCrypto, les chiffre avec une clé
+dérivée du mot de passe (PBKDF2-SHA512), et envoie le bundle chiffré au hub.
+À la prochaine connexion, le hub retourne le bundle et le navigateur le déchiffre
+localement. Le hub stocke le bundle mais ne peut pas le lire.
+Implémenté dans `static/keyderive.js`.
```
POST /v1/users/register
@@ -72,13 +89,15 @@ POST /v1/users/register
"username": "string",
"password": "string (min 8 chars)",
"pk_user_ed25519": "base64 raw 32-byte Ed25519 public key",
- "pk_user_x25519": "base64 raw 32-byte X25519 public key"
+ "pk_user_x25519": "base64 raw 32-byte X25519 public key",
+ "keypair_bundle": "base64 AES-256-GCM encrypted bundle (web clients only, optional)"
}
→ 201 {"user_id": "uuid"}
→ 409 if username is taken
```
-Passwords are hashed with Argon2id (iterations=4, memory=256 MB, target ~500ms on a home server). This is intentionally slow to limit offline dictionary attacks.
+Passwords are hashed with Argon2id (iterations=3, memory=64 MB in dev;
+target 256 MB / ~500ms in production). Intentionally slow to resist offline attacks.
### Login
@@ -86,13 +105,17 @@ Passwords are hashed with Argon2id (iterations=4, memory=256 MB, target ~500ms o
POST /v1/users/login
{"username": "yourname", "password": "yourpassword"}
→ {
- "access_token": "JWT (Ed25519, 1 hour validity)",
- "refresh_token": "opaque 256-bit token (30 days)",
- "token_type": "bearer",
- "expires_in": 3600
+ "access_token": "JWT (Ed25519, 1 hour validity)",
+ "refresh_token": "opaque 256-bit token (30 days)",
+ "token_type": "bearer",
+ "expires_in": 3600,
+ "keypair_bundle": "base64 AES-GCM blob (présent uniquement si enregistré via web)"
}
```
+Les clients web utilisent `keypair_bundle` pour récupérer leurs clés privées
+sur un nouvel appareil : déchiffrement local avec le mot de passe via `keyderive.js`.
+
```bash
curl -s -X POST https://meshbay.org/v1/users/login \
-H "Content-Type: application/json" \
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).