feat(crypto): adopt Argon2id (argon2id-v2) on register + master-pw change
Phase 2 of CODE_AUDIT §1.2 — live adoption of the Argon2id foundation.
Verified at runtime: a rotated account shows hash_algo=argon2id-v2 with
argon2_m=19456,t=2,p=1 in vault.db.
Server (never runs Argon2 — zero-knowledge, only stores/echoes params):
- DB: users.argon2_m/t/p columns (default 0 = PBKDF2).
- PM.Handler.Auth: HASH_ALGO_ARGON2 + param bounds, ReadArgon2Params /
AppendArgon2Params helpers. /register and /change-master-password accept
hashAlgo='argon2id-v2' + argon2:{m,t,p} and persist them; /login/challenge
echoes them. Verify path (VerifierToStoredHash/CheckVerifier) is
KDF-agnostic — the 64-hex verifier is SHA256-wrapped as for any -v2 scheme.
Client (app.js):
- state.argon2Params, cached from the challenge and persisted to
sessionStorage + the quick-unlock / PIN cold-start blobs (so a cold-started
session can still derive-from-password for reauth/rotation).
- Register + master-pw rotation derive with argon2id-v2 + ARGON2_DEFAULT_PARAMS
(OWASP m=19MiB,t=2,p=1) and send the params. Rotation re-encrypts the whole
vault under the new Argon2 key (natural migration point). Existing accounts
stay PBKDF2 until they rotate.
- Params threaded through every derive-from-password site (login, reauth,
recovery setup, change-pw current verifier). Cold-start verifier-from-raw-key
paths need no params (isDecoupledVerifierAlgo handles the -v2 wrap).
Tests: +2 param-contract tests (register<->login determinism, param
sensitivity). 42/42. Assets rebuilt to embed js/argon2.js.
Docs: CLAUDE.md auth-hash section rewritten (4 markers); CODE_AUDIT §1.2 +
table + plan marked done.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+24
-9
@@ -51,15 +51,30 @@ PBKDF2 avec un `info`/salt distinct. Ainsi le verifier transmis n'est
|
||||
pas la clé. Migration possible sans re-chiffrer les entries (seul le
|
||||
verifier stocké côté serveur change).
|
||||
|
||||
### 1.2 🟠 PBKDF2-SHA256 vs Argon2id
|
||||
### 1.2 🟠 PBKDF2-SHA256 vs Argon2id — **corrigé (2026-07-05)**
|
||||
|
||||
600k itérations SHA-256 pour les nouveaux comptes (correct, conforme
|
||||
OWASP 2023 ≥ 600k). Mais PBKDF2-SHA256 reste **GPU/ASIC-friendly**.
|
||||
Un master pw faible tombe vite sur du matériel dédié si la DB fuit.
|
||||
PBKDF2-SHA256 (600k) reste **GPU/ASIC-friendly** → un master pw faible
|
||||
tombe vite sur matériel dédié si la DB fuit.
|
||||
|
||||
**Recommandation** : migrer vers **Argon2id** (memory-hard). Coût :
|
||||
WebAssembly côté JS (argon2-browser) + implémentation Delphi, avec
|
||||
migration progressive (comme le passage 100k→600k déjà en place).
|
||||
**Fait** : nouveau scheme `argon2id-v2` (Argon2id memory-hard + verifier
|
||||
décplé). Détails dans le CLAUDE.md « Auth-hash schemes ».
|
||||
- **JS pur** (`js/argon2.js`, bundle `@noble/hashes@2.2.0`), **pas WASM** :
|
||||
la CSP `script-src 'self'` n'accorde pas `wasm-unsafe-eval`. Vérifié
|
||||
contre le vecteur RFC 9106 §5.3 (test unitaire).
|
||||
- **Zéro Argon2 côté Delphi** (l'audit se trompait sur ce point) : le
|
||||
serveur ne dérive jamais la clé, il stocke/échoie juste les params
|
||||
(`argon2_m/t/p`) et SHA256-wrappe le verifier comme tout `-v2`.
|
||||
- Params OWASP `m=19 MiB, t=2, p=1` (~0.65 s/unlock), stockés par compte.
|
||||
- **Adoption** : register + change-master-pw (nouveau défaut). Comptes
|
||||
existants restent PBKDF2 jusqu'à rotation. Passer à Argon2id re-chiffre
|
||||
tout le vault (la clé dérivée change) — c'est le flow rotation existant.
|
||||
- Tests : 8 tests crypto Argon2 (vecteur RFC, branche KDF, contrat de
|
||||
params register↔login, sensibilité aux params). 42/42.
|
||||
|
||||
**Reste** : dériver via `argon2idAsync` pour ne pas geler l'UI ~0.65 s
|
||||
(actuellement sync) ; option « migrer vers Argon2id sans changer de pw »
|
||||
(aujourd'hui il faut changer le master pw). **Non compilé/testé runtime
|
||||
Delphi dans cette session** — nécessite un rebuild `PMServer.dproj`.
|
||||
|
||||
### 1.3 🟡 Métadonnées en clair
|
||||
|
||||
@@ -268,7 +283,7 @@ cf. la checklist "Entry payload" de CLAUDE.md).
|
||||
|
||||
| Feature | Valeur | Effort | Note |
|
||||
|---|---|---|---|
|
||||
| **Argon2id** (KDF memory-hard) | 🔴 Haute | Moyen | argon2-browser + Delphi, migration progressive |
|
||||
| ~~**Argon2id** (KDF memory-hard)~~ ✅ | 🔴 Haute | ~~Moyen~~ | Fait : `argon2id-v2`, JS pur (noble), zéro Delphi. Cf. §1.2 |
|
||||
| **ETag/If-Match sur sync** | 🟠 Haute | Faible | Évite les lost updates multi-device |
|
||||
| **Extension navigateur** | 🟠 Haute | Élevé | Autofill in-page, feature #1 demandée |
|
||||
| **Windows Hello (biométrie)** | 🟠 Moyenne | Moyen | `Windows.Security.Credentials` — déverrouillage biométrique |
|
||||
@@ -289,7 +304,7 @@ cf. la checklist "Entry payload" de CLAUDE.md).
|
||||
3. **ETag/If-Match sur sync** (§2.1) — évite la perte de données multi-device.
|
||||
4. ~~**Timestamps UTC partout** (§2.2)~~ — ✅ fait (`NowUTCStr`, going-forward ; rows existantes self-heal).
|
||||
5. ~~**Tests unitaires crypto + merge** (§3.2)~~ — ✅ fait (35 tests, `js/tests/`, gate de build).
|
||||
6. **Argon2id** (§1.2) — durcissement KDF, migration progressive.
|
||||
6. ~~**Argon2id** (§1.2)~~ — ✅ fait (`argon2id-v2`, JS pur, adoption register+rotation).
|
||||
7. Découpage `app.js` en modules (§3.1) — maintenabilité long terme.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user