aboutsummaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-14 03:01:58 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-17 12:43:09 +0200
commit0370d001a4e74d2af0809a3e1eb5ada699b1bca2 (patch)
tree4eca51060cc94c04856c59765886523b70583b7c /CLAUDE.md
parent9d1d4a7af5844f50f168ff00818382ffe57c3452 (diff)
downloadmeshbay-0370d001a4e74d2af0809a3e1eb5ada699b1bca2.tar.gz
fix(hub): the password verifier is Argon2id 64 MiB, and a hash's version names its parameters
`pw_version` 4: Argon2id 64 MiB, t=3, lanes=4 — RFC 9106's second recommended setting. A v3 hash (256 MB) still verifies at its own parameters and is rewritten at the new ones on the next sign-in, through the rehash path that already existed. Why not more. The verifier matters against an offline attacker holding the database; online guessing is bounded by the sign-in lockout. That attacker pays the client's 600 000 PBKDF2-SHA512 iterations and the hub's Argon2id per guess, since `auth_key` is 256 bits and cannot be searched directly. Memory above 64 MiB multiplies that cost by a constant — at most 16 at 256 MB, less with PBKDF2 counted — while the hub pays the same memory at every sign-in, one derivation at a time. Measured on meshbay.org: 450 ms at 256 MB, 105 ms at 64 MiB, so a burst of sign-ins clears about four times faster. Changing the current version exposed a latent lockout. `hash_password` always used the current version's parameters, while the raw-password scheme recorded `pw_version = 2` — harmless while versions 2 and 3 shared their parameters, and with version 4 every legacy registration and v1→v2 rehash would have stored a 64 MiB hash labelled 256 MB, which nothing could then verify. Seventeen tests caught it. `hash_password` now takes the version it is hashing for. The OpenSSL deadlock between two concurrent `lanes=4` derivations is the same at 64 MiB, so Argon2 stays on its single worker. The loop-stall test measures against a v3 hash, because half of a 45 ms inline derivation is too close to scheduling noise to be a reliable bound. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LcF3QKWii7uQ2kSyXErzCt
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md13
1 files changed, 9 insertions, 4 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 164c541..384e86a 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -210,7 +210,8 @@ These are about working on the tree rather than about the design:
having a bad day. `mail.send_off_loop` is the door, and
`test_no_mail_is_sent_from_the_event_loop` reads the source for direct calls,
because there is nothing else to read. **Argon2 is the same, with a trap
- under it**: one derivation is 256 MB and ~0.25–0.5 s, so it goes through
+ under it**: one derivation is 64 MiB and ~0.1 s on meshbay.org (0.45 s at the
+ 256 MB of `pw_version` 3, still paid once per old account), so it goes through
`auth.hash_password_off_loop` / `verify_password_off_loop` — but **two
concurrent `lanes=4` derivations deadlock inside OpenSSL** and never return,
at no CPU (cryptography 50.0.x, OpenSSL 4.0.x, reproduced locally and on
@@ -723,9 +724,13 @@ older one wins by being read first.
## Known calibration TODOs
-- Argon2id `memory_cost`: ✅ DONE — bumped to 262144 (256 MB) in pw_version=2.
- Existing v1 users (64 MB) are transparently rehashed on next successful login.
- CLI `calibrate` command still TODO for per-hardware tuning.
+- Hub Argon2id verifier: **64 MiB, t=3, lanes=4 in `pw_version` 4** — why not
+ more is `docs/MESHBAY_DESIGN.md` §4.6. Older `auth_key` hashes (v3, 256 MB)
+ are rewritten on next sign-in; legacy raw-password hashes stay at v2.
+ **`hash_password` takes the version being stored** — hashing at one version's
+ parameters and recording another locks the account out, which went unseen
+ while v2 and v3 shared parameters. CLI `calibrate` still TODO for per-hardware
+ tuning.
## NAT traversal