Aller au contenu

PD-97 — Retour d'expérience


📚 Navigation User Story | Document | | | ---------- | -- | | 📋 [Spécification](PD-97-specification.md) | | | 🛠️ [Plan d'implémentation](PD-97-plan.md) | | | ✅ [Critères d'acceptation](PD-97-acceptability.md) | | | 📝 **Retour d'expérience** | *(ce document)* | [← Retour à mobile-ios](../PD-195-epic.md) · [↑ Index User Story](index.md)

1. Résumé exécutif

La User Story PD-97 visait à implémenter un pipeline cryptographique client-side zero-knowledge pour iOS, incluant AES-256-GCM, gestion des enveloppes K_master, et effacement mémoire sécurisé. L'implémentation est fonctionnelle et fournit les primitives crypto nécessaires, mais présente 3 écarts MAJEURS (dépendance WASM/asm.js non validée en prod, opérations sur UI thread, zeroization incomplète) et 1 écart MINEUR (AAD optionnel). Verdict : ACCEPTÉ AVEC RÉSERVES.


2. Points fluides

  • Architecture modulaire : structure src/crypto/ claire avec séparation aes-gcm, envelope, zeroize, constants, types, utils
  • @noble/ciphers : bibliothèque pure JavaScript sans dépendance WASM, fonctionne sur Hermes
  • Polyfill WebAssembly : solution élégante qui définit un stub WASM pour forcer argon2-browser en mode asm.js
  • Documentation zeroization : limitations JavaScript clairement documentées dans le code (strings immutables, GC)
  • SecureBuffer class : wrapper avec destruction explicite et vérification d'état
  • withZeroize patterns : helpers try/finally pour garantir cleanup même en cas d'erreur
  • Tests Vitest : configuration dédiée pour modules ESM (@noble/ciphers)
  • Envelope API complète : create, open, rewrap, validate, serialize/deserialize

3. Points difficiles

Difficulté Contexte
Hermes sans WASM Le moteur JavaScript de React Native ne supporte pas WebAssembly, nécessitant un fallback asm.js
Strings JavaScript immutables Impossible d'effacer les mots de passe/clés stockés en string, uniquement déréférencement
Argon2id 64 MiB Allocation mémoire importante qui freeze l'UI sans worker offloading
Validation production Le polyfill WASM n'est pas validé avec EAS builds, risque de régression en release
Dual test runner Jest incompatible avec @noble/* (ESM), nécessitant Vitest séparé

4. Hypothèses révélées tardivement

Hypothèse initiale Réalité découverte
Hermes supporte WebAssembly FAUX — WASM non disponible, polyfill nécessaire pour asm.js fallback
JavaScript permet effacement mémoire FAUX — Strings immutables, GC peut conserver des copies, "best-effort" seulement
Argon2id s'exécute sans blocage UI FAUX — 64 MiB allocation synchrone, freeze perceptible sur devices lents
@noble/ciphers nécessite WASM FAUX — Pure JavaScript, fonctionne parfaitement sur Hermes
Un seul test runner suffit FAUX — Jest pour React Native, Vitest pour modules ESM-only

5. Invariants complexes à implémenter

Invariant Complexité
Zero-knowledge strict Aucune clé, password ou plaintext ne doit quitter l'appareil — vérifié par architecture
IV unique par chiffrement Chaque encrypt() génère un nouvel IV via expo-crypto CSPRNG
Zeroization systématique try/finally avec zeroize() sur tous les buffers sensibles après usage
Tag 16 bytes GCM authentication tag fixé à 128 bits, non configurable
Envelope versioning ENVELOPE_VERSION dans constants.ts pour migration future

6. Dette technique

Dette Impact Priorité
Argon2id sur UI thread UX dégradée (freeze 2-5s sur devices lents) HAUTE
Zeroization incomplète K_master, K_doc, plaintexts fichiers non effacés systématiquement HAUTE
Validation EAS manquante Polyfill WASM non testé en production builds HAUTE
AAD optionnel Permet chiffrement sans contexte authentifié MOYENNE
Strings jamais effacées Passwords en mémoire jusqu'au GC MOYENNE

7. Risques résiduels

Risque Probabilité Impact Mitigation suggérée
Polyfill WASM échoue en prod Moyenne ÉLEVÉ Tester avec EAS build --profile production
UI freeze Argon2id Élevée MOYEN Migrer vers InteractionManager ou native module
Clés en mémoire après usage Élevée MOYEN SecureBuffer systématique + audit usage
Régression @noble version Faible MOYEN Lock versions dans package.json
Attaque memory dump Faible ÉLEVÉ Documenter comme limitation connue

8. Améliorations processus

Amélioration Bénéfice attendu
Tester polyfill avec EAS builds Valider comportement asm.js en production
Migrer Argon2id vers native Supprimer freeze UI via react-native-argon2 ou Turbo Module
SecureBuffer partout Wrapper systématique pour toutes les clés dérivées
Rendre AAD obligatoire Forcer contexte authentifié sur tous les chiffrements
Audit zeroization Vérifier tous les points de sortie des clés et plaintexts
Worker crypto Offloader opérations lourdes hors thread JS principal

9. Enseignements clés

  1. Hermes a des limitations critiques — Le moteur JavaScript de React Native ne supporte pas WebAssembly. Toute bibliothèque crypto dépendant de WASM doit avoir un fallback vérifié (asm.js ou pure JS).

  2. JavaScript n'est pas conçu pour la sécurité mémoire — Les strings sont immutables, le GC est non déterministe, les buffers peuvent être copiés en interne. L'effacement mémoire est "best-effort" et doit être documenté comme tel.

  3. Les opérations crypto lourdes bloquent l'UI — Sans worker ou InteractionManager, Argon2id avec 64 MiB freeze l'application. C'est un UX problem critique pour l'inscription/connexion.

  4. @noble/ciphers est un excellent choix — Bibliothèque pure JavaScript, auditée, sans dépendance WASM. Parfaitement compatible avec Hermes et l'écosystème React Native.

  5. Les polyfills doivent être validés en conditions réelles — Un polyfill qui fonctionne en développement (Expo Go) peut échouer en production (EAS builds). Toujours tester le chemin critique avec le profil de build final.