PD-35 — Plan d'implémentation¶
📚 Navigation User Story
| Document | | | ---------- | -- | | 📋 [Spécification](PD-35-specification.md) | | | 🛠️ **Plan d'implémentation** | *(ce document)* | | ✅ [Critères d'acceptation](PD-35-acceptability.md) | | | 📝 [Retour d'expérience](PD-35-rex.md) | | [← Retour à crypto-proof](../PD-189-epic.md) · [↑ Index User Story](index.md)Objectif¶
Implémenter le module d'enveloppes de clés (Key Wrapping) pour protéger K_master_user sans re-chiffrer les documents.
Choix techniques retenus¶
- Algorithme : AES-256-KW (RFC 3394)
- Bibliothèque : Node.js crypto (aes-256-wrap)
- Types : master, device, recovery
- Stockage : Table
vault_secure.key_envelopes
Architecture ciblée¶
src/modules/crypto/
├── services/
│ ├── aes-kw.service.ts # AES Key Wrap
│ └── key-envelope.service.ts # Gestion enveloppes
├── controllers/
│ └── key-envelope.controller.ts # API endpoints
├── entities/
│ ├── key-envelope.entity.ts
│ └── device-blacklist.entity.ts
└── dto/
├── create-master-envelope.dto.ts
├── create-device-envelope.dto.ts
└── create-recovery-envelope.dto.ts
Découpage technique¶
Phase 1 : AES-256-KW Service¶
- Implémenter
wrap(kek, plaintext): - Valider KEK 32 bytes
- Valider plaintext 32 bytes
-
Retourner 40 bytes (32 + 8 IV)
-
Implémenter
unwrap(kek, wrapped): - Valider wrapped 40 bytes
- Vérifier IV A6A6A6A6A6A6A6A6
-
Retourner plaintext 32 bytes
-
Utiliser crypto.createCipheriv('aes-256-wrap')
Phase 2 : Entités¶
- Créer
KeyEnvelopeentity :
@Entity('key_envelopes', { schema: 'vault_secure' })
export class KeyEnvelope {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('uuid')
userId: string;
@Column({ type: 'enum', enum: ['master', 'device', 'recovery'] })
type: EnvelopeType;
@Column('bytea')
wrappedKey: Buffer;
@Column({ nullable: true })
deviceId?: string;
@CreateDateColumn()
createdAt: Date;
@Column({ nullable: true })
revokedAt?: Date;
}
- Créer
DeviceBlacklistentity
Phase 3 : Key Envelope Service¶
createMasterEnvelope(userId, wrappedKey):- Valider format wrapped key
- Créer enveloppe type=master
-
Une seule active par user
-
createDeviceEnvelope(userId, deviceId, wrappedKey): - Vérifier device non blacklisté
-
Créer enveloppe type=device
-
createRecoveryEnvelope(userId, wrappedKey): - Créer enveloppe type=recovery
-
Une seule active par user
-
revokeDeviceEnvelope(userId, deviceId, reason): - Marquer enveloppe révoquée
- Ajouter à blacklist
Phase 4 : Controller¶
POST /crypto/envelopes/master:-
Créer enveloppe master
-
POST /crypto/envelopes/device: -
Créer enveloppe device
-
GET /crypto/envelopes: -
Lister enveloppes actives
-
DELETE /crypto/envelopes/device/:id: - Révoquer device
Phase 5 : Transactions¶
- Rotation password :
- Transaction atomique
- Créer nouvelle enveloppe master
-
Marquer ancienne révoquée
-
Révocation device :
- Transaction atomique
- Révoquer + blacklist
Phase 6 : Tests¶
- Tests wrap/unwrap conformité RFC 3394
- Tests unicité enveloppe master
- Tests révocation device
- Tests blacklist device
Points de vigilance¶
- KEK : Jamais stockée, dérivée du password
- wrapped_key : Seul élément persisté
- Blacklist : Permanent, pas de réactivation
- Transactions : Atomiques pour cohérence
Hors périmètre¶
- Dérivation KEK (→ PD-33 côté client)
- Chiffrement documents (→ PD-97 côté client)
- HSM pour clés (→ PD-36)