PD-34 — Plan d'implémentation¶
📚 Navigation User Story
| Document | | | ---------- | -- | | 📋 [Spécification](PD-34-specification.md) | | | 🛠️ **Plan d'implémentation** | *(ce document)* | | ✅ [Critères d'acceptation](PD-34-acceptability.md) | | | 📝 [Retour d'expérience](PD-34-rex.md) | | [← Retour à crypto](../PD-189-epic.md) · [↑ Index User Story](index.md)Objectif¶
Implémenter la dérivation HKDF-SHA3-256 pour générer K_doc (clé unique par document) depuis K_master_user.
Choix techniques retenus¶
- Algorithme : HKDF avec SHA3-256 (RFC 5869)
- Bibliothèque :
@noble/hashes(sha3, hkdf) - Hiérarchie : K_master → K_share → K_doc
- Domain separation : Salt=UUID document, Info=contexte fixe
Architecture ciblée¶
src/services/hkdf.ts
├── hkdfExtract() → PRK extraction
├── hkdfExpand() → OKM expansion
├── deriveShareKey() → K_share depuis K_master
├── deriveDocumentKey() → K_doc depuis K_share + docId
└── deriveDocumentHashKey() → K_hash optionnel
src/crypto/keys.ts
├── generateKMaster() → Génération K_master (32 bytes)
├── deriveKShare() → Wrapper hex API
├── deriveKDoc() → Wrapper hex API
└── deriveKDocFromMaster() → Raccourci K_master → K_doc
Découpage technique¶
Phase 1 : Primitives HKDF¶
- Implémenter
hkdfExtract(salt, ikm)→ PRK - Implémenter
hkdfExpand(prk, info, length)→ OKM - Utiliser
@noble/hashes/sha3pour SHA3-256 - Définir constantes
HKDF_CONTEXTSetKEY_LENGTH
Phase 2 : Dérivation K_share¶
- Implémenter
deriveShareKey(kMaster): - Salt :
"ProbatioVault::Share::v1"encodé UTF-8 - Info : vide
- Output : 32 bytes
Phase 3 : Dérivation K_doc¶
- Implémenter
uuidToBytes(uuid)→ 16 bytes - Implémenter
deriveDocumentKey(kShare, docId): - Salt : UUID document converti en 16 bytes
- Info :
"ProbatioVault::Kdoc::v1" - Output : 32 bytes
Phase 4 : API haut niveau (keys.ts)¶
generateKMaster()→ Crypto.getRandomBytes(32)deriveKShare(kMasterHex)→ hex wrapperderiveKDoc(kShareHex, docId)→ hex wrapperderiveKDocFromMaster(kMasterHex, docId)→ chaînage complet- Validation
isValidKey(),isValidSalt()
Phase 5 : Sécurité mémoire¶
- Import et usage de
zeroize()pour effacement - Effacer clés intermédiaires après usage
- Re-export depuis keys.ts pour API unifiée
Phase 6 : Tests¶
- Tests vecteurs HKDF (RFC 5869 test vectors)
- Tests déterminisme (même input → même output)
- Tests isolation (docId différent → K_doc différent)
- Tests validation UUID
Points de vigilance¶
- UUID format : Doit être valide (36 chars avec tirets)
- Conversion UUID : Retirer tirets, convertir hex → 16 bytes
- Zeroization : Appeler systématiquement sur clés intermédiaires
- Re-exports : Centraliser API dans keys.ts
Hors périmètre¶
- Dérivation Argon2id initiale (→ PD-33)
- Chiffrement AES-256-GCM (→ PD-97)
- Gestion enveloppes (→ PD-35 backend)