Aller au contenu

PD-98 — Plan d'implémentation


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

Objectif

Stocker K_master de manière sécurisée dans le iOS Keychain avec les attributs de sécurité maximaux.

Choix techniques retenus

  • Bibliothèque : expo-secure-store
  • Attribut iOS : WHEN_UNLOCKED_THIS_DEVICE_ONLY
  • Encodage : Base64 pour stockage string
  • Versioning : Clé préfixée com.probatiovault.kmaster.v1

Architecture ciblée

src/services/keychainStorage.ts
├── storeMasterKey(kMaster)      → Stocke K_master
├── getMasterKey()               → Récupère K_master
├── deleteMasterKey()            → Supprime K_master
├── existsMasterKey()            → Vérifie existence
└── clearMasterKeyBuffer()       → Efface de la mémoire

Découpage technique

Phase 1 : Configuration SecureStore

  1. Définir KEYCHAIN_OPTIONS avec :
  2. keychainAccessible: WHEN_UNLOCKED_THIS_DEVICE_ONLY
  3. Pas de sync iCloud
  4. Non migrable entre appareils

  5. Définir constantes :

  6. KMASTER_KEY = "com.probatiovault.kmaster.v1"
  7. KMASTER_SIZE = 32 (256 bits)

Phase 2 : Encodage Base64

  1. Implémenter uint8ToBase64(bytes) :
  2. Conversion native (pas de btoa en RN)
  3. Utiliser alphabet standard

  4. Implémenter base64ToUint8(b64) :

  5. Conversion inverse
  6. Gérer padding

Phase 3 : Opérations CRUD

  1. storeMasterKey(kMaster: Uint8Array) :
  2. Vérifier disponibilité SecureStore
  3. Valider taille (32 bytes exactement)
  4. Encoder base64 et stocker
  5. Retourner KeychainResult<void>

  6. getMasterKey() :

  7. Lire depuis SecureStore
  8. Décoder base64
  9. Valider taille
  10. Retourner KeychainResult<Uint8Array>

  11. deleteMasterKey() :

  12. Supprimer de SecureStore
  13. Ignorer erreur si inexistant

  14. existsMasterKey() :

  15. Vérification légère sans lecture complète

Phase 4 : Gestion erreurs

  1. Définir KeychainError enum :
  2. NOT_AVAILABLE (plateforme non supportée)
  3. DEVICE_LOCKED (appareil verrouillé)
  4. NOT_FOUND (clé inexistante)
  5. INVALID_KEY_SIZE (taille incorrecte)
  6. ENCODING_ERROR (base64 corrompu)

  7. Implémenter mapError(error) :

  8. Analyser message d'erreur
  9. Retourner code approprié
  10. JAMAIS logger données sensibles

Phase 5 : Sécurité

  1. clearBuffer(buffer) :
  2. Remplir avec zéros
  3. Appeler après usage

  4. Logs sécurisés :

  5. Jamais la valeur de K_master
  6. Uniquement événements (success/failure)

  7. Exposer __test__ pour tests unitaires

Phase 6 : Tests

  1. Tests stockage/récupération
  2. Tests suppression
  3. Tests erreurs (taille invalide, non disponible)
  4. Tests plateforme (iOS vs Android vs Web)

Points de vigilance

  • Platform.OS : SecureStore non disponible sur web
  • Device locked : Peut échouer si appareil verrouillé
  • Migration : Clé NON transférée lors de restauration backup
  • Versioning : Prévoir migration si format change

Hors périmètre

  • Dérivation K_master (→ PD-33)
  • Chiffrement avec K_master (→ PD-97)
  • Biométrie/Face ID (→ future US)