Aller au contenu

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

  1. Implémenter hkdfExtract(salt, ikm) → PRK
  2. Implémenter hkdfExpand(prk, info, length) → OKM
  3. Utiliser @noble/hashes/sha3 pour SHA3-256
  4. Définir constantes HKDF_CONTEXTS et KEY_LENGTH

Phase 2 : Dérivation K_share

  1. Implémenter deriveShareKey(kMaster) :
  2. Salt : "ProbatioVault::Share::v1" encodé UTF-8
  3. Info : vide
  4. Output : 32 bytes

Phase 3 : Dérivation K_doc

  1. Implémenter uuidToBytes(uuid) → 16 bytes
  2. Implémenter deriveDocumentKey(kShare, docId) :
  3. Salt : UUID document converti en 16 bytes
  4. Info : "ProbatioVault::Kdoc::v1"
  5. Output : 32 bytes

Phase 4 : API haut niveau (keys.ts)

  1. generateKMaster() → Crypto.getRandomBytes(32)
  2. deriveKShare(kMasterHex) → hex wrapper
  3. deriveKDoc(kShareHex, docId) → hex wrapper
  4. deriveKDocFromMaster(kMasterHex, docId) → chaînage complet
  5. Validation isValidKey(), isValidSalt()

Phase 5 : Sécurité mémoire

  1. Import et usage de zeroize() pour effacement
  2. Effacer clés intermédiaires après usage
  3. Re-export depuis keys.ts pour API unifiée

Phase 6 : Tests

  1. Tests vecteurs HKDF (RFC 5869 test vectors)
  2. Tests déterminisme (même input → même output)
  3. Tests isolation (docId différent → K_doc différent)
  4. 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)