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¶
- Définir
KEYCHAIN_OPTIONSavec : keychainAccessible: WHEN_UNLOCKED_THIS_DEVICE_ONLY- Pas de sync iCloud
-
Non migrable entre appareils
-
Définir constantes :
KMASTER_KEY = "com.probatiovault.kmaster.v1"KMASTER_SIZE = 32(256 bits)
Phase 2 : Encodage Base64¶
- Implémenter
uint8ToBase64(bytes): - Conversion native (pas de btoa en RN)
-
Utiliser alphabet standard
-
Implémenter
base64ToUint8(b64): - Conversion inverse
- Gérer padding
Phase 3 : Opérations CRUD¶
storeMasterKey(kMaster: Uint8Array):- Vérifier disponibilité SecureStore
- Valider taille (32 bytes exactement)
- Encoder base64 et stocker
-
Retourner
KeychainResult<void> -
getMasterKey(): - Lire depuis SecureStore
- Décoder base64
- Valider taille
-
Retourner
KeychainResult<Uint8Array> -
deleteMasterKey(): - Supprimer de SecureStore
-
Ignorer erreur si inexistant
-
existsMasterKey(): - Vérification légère sans lecture complète
Phase 4 : Gestion erreurs¶
- Définir
KeychainErrorenum : NOT_AVAILABLE(plateforme non supportée)DEVICE_LOCKED(appareil verrouillé)NOT_FOUND(clé inexistante)INVALID_KEY_SIZE(taille incorrecte)-
ENCODING_ERROR(base64 corrompu) -
Implémenter
mapError(error): - Analyser message d'erreur
- Retourner code approprié
- JAMAIS logger données sensibles
Phase 5 : Sécurité¶
clearBuffer(buffer):- Remplir avec zéros
-
Appeler après usage
-
Logs sécurisés :
- Jamais la valeur de K_master
-
Uniquement événements (success/failure)
-
Exposer
__test__pour tests unitaires
Phase 6 : Tests¶
- Tests stockage/récupération
- Tests suppression
- Tests erreurs (taille invalide, non disponible)
- 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)