Aller au contenu

PD-242 — Enveloppe cryptographique de recuperation (K_recovery)


Navigation User Story | Document | | | ---------- | -- | | Specification | *(ce document)* | | [Plan d'implementation](PD-242-plan.md) | | | [Criteres d'acceptation](PD-242-acceptability.md) | | | [Retour d'experience](PD-242-rex.md) | | [← Retour a crypto](../PD-189-epic.md) · [Index User Story](index.md)

References

  • EPIC : PD-189 — CRYPTO
  • JIRA : PD-242
  • Composant : Client-side crypto (mobile iOS)

Objectif

Implementer un mecanisme de recovery cryptographique permettant a l'utilisateur de recuperer l'acces a son coffre-fort numerique en cas de perte ou remplacement de son appareil iOS, via une phrase de recuperation BIP-39 de 24 mots.

Ce mecanisme garantit la promesse d'architecture zero-knowledge : le backend stocke uniquement l'enveloppe chiffree (Recovery_Envelope) sans jamais pouvoir acceder a la cle maitre utilisateur (K_master_user).

La phrase de recuperation n'est jamais stockee (ni localement, ni cote backend). Seul l'utilisateur en possede une copie physique.

Description fonctionnelle

Flux 1 : Creation de la recovery (onboarding obligatoire)

Lors de la creation de compte ProbatioVault :

  1. K_master_user est generee et stockee dans le Keychain iOS (PD-98)
  2. L'application genere une phrase BIP-39 de 24 mots via CSPRNG local
  3. L'application affiche la phrase avec protection screenshot
  4. L'affichage expire apres 120 secondes (masquage automatique)
  5. L'utilisateur DOIT re-saisir les 24 mots complets pour confirmer
  6. K_recovery est derivee via HKDF-SHA3-256
  7. Recovery_Envelope est creee : Enc_AES-256-GCM(K_recovery, K_master_user)
  8. H_verify est genere : SHA3-256(K_recovery || user_id)
  9. Recovery_Envelope + H_verify sont envoyes au backend (zero-knowledge)
  10. K_recovery est detruite en memoire IMMEDIATEMENT
  11. La phrase n'est JAMAIS stockee

Flux 2 : Restauration sur nouveau device

Lorsqu'un utilisateur installe ProbatioVault sur un nouveau device :

  1. L'application detecte l'absence de K_master dans le Keychain local
  2. L'ecran propose "Recuperer mon coffre" ou "Creer un nouveau compte"
  3. L'utilisateur choisit "Recuperer mon coffre" et saisit ses 24 mots
  4. K_recovery est derivee localement (memes parametres)
  5. H_verify_candidate = SHA3-256(K_recovery || user_id)
  6. L'application demande H_verify au backend et compare
  7. Si match : l'application demande Recovery_Envelope au backend
  8. K_master_user = Dec_AES-256-GCM(K_recovery, Recovery_Envelope)
  9. K_master_user est stockee dans le nouveau Keychain (PD-98)
  10. K_recovery est detruite en memoire IMMEDIATEMENT
  11. L'utilisateur recupere l'acces a son coffre

Flux 3 : Regeneration de phrase (sur demande utilisateur)

Lorsqu'un utilisateur souhaite regenerer sa phrase de recovery :

  1. L'application demande l'authentification forte (biometrie + password)
  2. Une nouvelle phrase BIP-39 de 24 mots est generee
  3. L'affichage expire apres 120 secondes
  4. L'utilisateur DOIT re-saisir les 24 mots complets
  5. Une nouvelle K_recovery est derivee
  6. Une nouvelle Recovery_Envelope est creee
  7. L'ancienne Recovery_Envelope est invalidee cote backend
  8. Nouvelle Recovery_Envelope + H_verify envoyes au backend
  9. Nouvelle K_recovery detruite IMMEDIATEMENT

5bis. Diagrammes

5bis.1 Diagramme d'etats — Recovery Envelope

stateDiagram-v2
    [*] --> NO_ENVELOPE : Compte cree / nouveau device

    state "Flux Creation (onboarding)" as creation {
        NO_ENVELOPE --> PHRASE_DISPLAYED : generateMnemonic() [INV-242-05]
        PHRASE_DISPLAYED --> PHRASE_EXPIRED : timeout 120s [INV-242-12]
        PHRASE_EXPIRED --> PHRASE_DISPLAYED : re-affichage (auth)
        PHRASE_DISPLAYED --> PHRASE_CONFIRMED : re-saisie 24 mots OK [INV-242-09]
        PHRASE_CONFIRMED --> K_RECOVERY_DERIVED : HKDF-SHA3-256 [INV-242-06]
        K_RECOVERY_DERIVED --> ENVELOPE_STORED : Enc AES-256-GCM + POST backend [INV-242-07, INV-242-01]
        ENVELOPE_STORED --> K_RECOVERY_WIPED : fill(0) immediat [INV-242-03]
    }

    state "Flux Restauration (nouveau device)" as restoration {
        NO_ENVELOPE --> RECOVERY_INITIATED : "Recuperer mon coffre"
        RECOVERY_INITIATED --> VERIFY_PENDING : deriveRecoveryKey() + computeVerificationHash() [INV-242-08]
        VERIFY_PENDING --> VERIFY_FAILED : H_verify mismatch
        VERIFY_PENDING --> VERIFY_SUCCESS : H_verify match
        VERIFY_FAILED --> RECOVERY_INITIATED : nouvelle tentative (< 5/15min) [INV-242-13]
        VERIFY_FAILED --> RATE_LIMITED : >= 5 echecs / 15 min [INV-242-13]
        RATE_LIMITED --> RECOVERY_INITIATED : apres expiration fenetre 15 min
        VERIFY_SUCCESS --> ENVELOPE_DECRYPTED : Dec AES-256-GCM [INV-242-07]
        ENVELOPE_DECRYPTED --> RESTORED : K_master -> Keychain [INV-242-04]
        RESTORED --> K_RECOVERY_WIPED_R : fill(0) immediat [INV-242-03]
    }

    state "Flux Regeneration" as regeneration {
        ENVELOPE_STORED --> REGEN_AUTH : auth forte (biometrie + password)
        REGEN_AUTH --> REGEN_PHRASE_DISPLAYED : nouvelle phrase BIP-39 [INV-242-05]
        REGEN_PHRASE_DISPLAYED --> REGEN_PHRASE_EXPIRED : timeout 120s [INV-242-12]
        REGEN_PHRASE_EXPIRED --> REGEN_PHRASE_DISPLAYED : re-affichage (auth)
        REGEN_PHRASE_DISPLAYED --> REGEN_PHRASE_CONFIRMED : re-saisie 24 mots OK [INV-242-09]
        REGEN_PHRASE_CONFIRMED --> OLD_ENVELOPE_INVALIDATED : DELETE ancien [INV-242-02]
        OLD_ENVELOPE_INVALIDATED --> NEW_ENVELOPE_STORED : POST nouveau [INV-242-01, INV-242-07]
        NEW_ENVELOPE_STORED --> K_RECOVERY_WIPED_RG : fill(0) immediat [INV-242-03]
    }

    K_RECOVERY_WIPED --> [*] : Onboarding termine
    K_RECOVERY_WIPED_R --> [*] : Coffre restaure
    K_RECOVERY_WIPED_RG --> [*] : Regeneration terminee

    note right of RATE_LIMITED : 429 Too Many Requests\n5 tentatives / 15 min / user_id\n20 tentatives / 15 min / IP
    note right of K_RECOVERY_WIPED : INV-242-02 : phrase JAMAIS stockee\nINV-242-03 : K_recovery detruite

5bis.2 Diagramme de sequence — Flux complet (creation + restauration + regeneration)

sequenceDiagram
    actor User
    participant App as App iOS
    participant Crypto as RecoveryService<br/>(client-side)
    participant Keychain as Keychain iOS
    participant Backend as Backend API

    note over User, Backend: ━━━ FLUX 1 : Creation (onboarding) ━━━

    User->>App: Creer un compte
    App->>Keychain: Lire K_master_user (PD-98)
    Keychain-->>App: K_master_user

    App->>Crypto: generateMnemonic()
    note right of Crypto: SecRandomCopyBytes<br/>256 bits entropie<br/>+ checksum 8 bits SHA-256<br/>[INV-242-05]
    Crypto-->>App: phrase (24 mots BIP-39)

    App->>User: Afficher phrase (screenshot protege) [INV-242-11]
    note right of App: Timer 120s demarre [INV-242-12]

    User->>App: Re-saisir 24 mots [INV-242-09]
    App->>App: Validation complete (24/24 mots)

    App->>Crypto: deriveRecoveryKey(phrase, user_id)
    note right of Crypto: BIP-39 seed : PBKDF2-HMAC-SHA512<br/>(2048 iter, passphrase="")<br/>K_recovery : HKDF-SHA3-256<br/>(salt="ProbatioVault::Recovery::v1",<br/>info=user_id, len=32)<br/>[INV-242-06]
    Crypto-->>App: K_recovery (32 bytes)

    App->>Crypto: createRecoveryEnvelope(K_recovery, K_master_user)
    note right of Crypto: AES-256-GCM<br/>nonce=96 bits random<br/>tag=128 bits<br/>[INV-242-07]
    Crypto-->>App: {envelope, nonce, tag}

    App->>Crypto: computeVerificationHash(K_recovery, user_id)
    note right of Crypto: H_verify = SHA3-256(K_recovery || user_id)<br/>[INV-242-08]
    Crypto-->>App: H_verify

    App->>Backend: POST /recovery/envelope {user_id, envelope, h_verify}
    note right of App: Seuls envelope (ciphertext)<br/>et H_verify (hash) transitent<br/>[INV-242-01, INV-242-04]
    Backend-->>App: 201 Created
    Backend->>Backend: Trace recovery.envelope.created

    App->>Crypto: wipeKey(K_recovery)
    note right of Crypto: Uint8Array.fill(0)<br/>[INV-242-03]

    note over App: Phrase JAMAIS stockee [INV-242-02]

    note over User, Backend: ━━━ FLUX 2 : Restauration (nouveau device) ━━━

    User->>App: Installer sur Device B
    App->>Keychain: Lire K_master_user
    Keychain-->>App: null (absent)

    App->>User: "Recuperer mon coffre" / "Creer un compte"
    User->>App: "Recuperer mon coffre"
    User->>App: Saisir 24 mots [INV-242-10]

    App->>Crypto: deriveRecoveryKey(phrase, user_id)
    Crypto-->>App: K_recovery

    App->>Crypto: computeVerificationHash(K_recovery, user_id)
    Crypto-->>App: H_verify_candidate

    App->>Backend: GET /recovery/h_verify/:user_id
    Backend-->>App: {h_verify}
    Backend->>Backend: Trace recovery.restore.attempt

    alt H_verify mismatch
        App->>User: Erreur : phrase incorrecte
        Backend->>Backend: Trace recovery.restore.failed (hash_mismatch)
        note right of Backend: Rate limit : 5 tentatives/15min<br/>[INV-242-13]
    else H_verify match
        App->>Backend: GET /recovery/envelope/:user_id<br/>X-H-Verify-Candidate: H_verify_candidate
        Backend-->>App: {envelope}

        App->>Crypto: restoreFromEnvelope(K_recovery, envelope)
        note right of Crypto: Dec AES-256-GCM<br/>[INV-242-07]
        Crypto-->>App: K_master_user

        App->>Keychain: Stocker K_master_user (PD-98)
        Backend->>Backend: Trace recovery.restore.success (device_id)

        App->>Crypto: wipeKey(K_recovery)
        note right of Crypto: [INV-242-03]

        App->>User: Coffre restaure
    end

    note over User, Backend: ━━━ FLUX 3 : Regeneration ━━━

    User->>App: Regenerer ma phrase
    App->>User: Authentification forte (biometrie + password)
    User->>App: Auth OK

    App->>Crypto: generateMnemonic()
    Crypto-->>App: nouvelle phrase (24 mots)

    App->>User: Afficher nouvelle phrase [INV-242-11, INV-242-12]
    User->>App: Re-saisir 24 mots [INV-242-09]

    App->>Crypto: deriveRecoveryKey(nouvelle_phrase, user_id)
    Crypto-->>App: nouvelle K_recovery

    App->>Crypto: createRecoveryEnvelope(nouvelle_K_recovery, K_master_user)
    Crypto-->>App: {nouvelle_envelope, nonce, tag}

    App->>Crypto: computeVerificationHash(nouvelle_K_recovery, user_id)
    Crypto-->>App: nouveau H_verify

    App->>Backend: DELETE /recovery/envelope/:user_id
    Backend-->>App: 204 No Content
    note right of Backend: Ancienne envelope invalidee<br/>(ancienne phrase inutilisable)

    App->>Backend: POST /recovery/envelope {user_id, nouvelle_envelope, nouveau_h_verify}
    Backend-->>App: 201 Created
    Backend->>Backend: Trace recovery.envelope.regenerated

    App->>Crypto: wipeKey(nouvelle_K_recovery)
    note right of Crypto: [INV-242-03]

Perimetre

Inclus

  • Generation phrase BIP-39 24 mots (CSPRNG local via SecRandomCopyBytes)
  • Derivation K_recovery via HKDF-SHA3-256 avec domain separation
  • Creation Recovery_Envelope (AES-256-GCM)
  • Hash de verification H_verify
  • API backend pour stocker/recuperer l'envelope (zero-knowledge)
  • Flux de confirmation (re-saisie 24 mots)
  • Flux de restauration sur nouveau device
  • Flux de regeneration sur demande
  • Protection screenshot de l'affichage phrase
  • Timeout affichage phrase (120 secondes)
  • Rate limiting des tentatives de restauration
  • Destruction memoire K_recovery apres usage
  • Tests avec vecteurs BIP-39 officiels

Exclu

  • Stockage iCloud de l'envelope (decision : backend only)
  • Rotation automatique de l'envelope
  • Shamir Secret Sharing (2-of-3) — future story
  • Mode enterprise custody — future story
  • Implementation Android/Web — hors scope iOS
  • UX de sauvegarde phrase (papier, coffre physique) — responsabilite utilisateur

Parametres cryptographiques normatifs

Parametre Valeur Reference Testable
Phrase format BIP-39 (24 mots, 256 bits) BIP-0039 Oui
Wordlist BIP-39 English (2048 mots) BIP-0039 Oui
Phrase entropy 256 bits BIP-0039 Oui
Phrase checksum 8 bits (SHA-256) BIP-0039 Oui
Seed derivation PBKDF2-HMAC-SHA512 BIP-0039 Oui
PBKDF2 iterations 2048 BIP-0039 Oui
PBKDF2 passphrase "" (vide) BIP-0039 Oui
Derivation K_recovery HKDF-SHA3-256 RFC 5869 + FIPS 202 Oui
HKDF salt "ProbatioVault::Recovery::v1" (UTF-8) Domain separation Oui
HKDF info user_id (UUID bytes) Context binding Oui
HKDF output length 32 bytes (256 bits) Coherence K_master Oui
Chiffrement envelope AES-256-GCM NIST SP 800-38D Oui
GCM key K_recovery (32 bytes) Oui
GCM nonce 96 bits (random) Best practice Oui
GCM tag length 128 bits NIST Oui
Hash verification SHA3-256(K_recovery || user_id) FIPS 202 Oui
Timeout affichage 120 secondes UX Oui
Rate limit restore 5 tentatives / 15 minutes / user_id SEC Oui
Rate limit IP 20 tentatives / 15 minutes / IP SEC Oui

Proprietes attendues

Securite

  • Resistance aux attaques par dictionnaire sur la phrase (256 bits d'entropie)
  • Couplage obligatoire phrase + user_id + domain separation
  • Aucune fuite de K_recovery via logs, stacktraces ou exceptions
  • Protection contre le screenshot de la phrase affichee
  • Masquage automatique de la phrase apres timeout
  • Rate limiting des tentatives de restauration (protection brute-force backend)
  • Effacement memoire best-effort de K_recovery apres usage (Uint8Array.fill(0))

Zero-Knowledge

  • La phrase ne quitte JAMAIS l'appareil
  • K_recovery ne transite JAMAIS en clair sur le reseau
  • Le backend ne peut PAS dechiffrer K_master_user
  • Seuls Recovery_Envelope (ciphertext) et H_verify (hash) sont stockes backend
  • Aucun log backend ne contient de materiel cryptographique sensible

Interoperabilite

  • Resultat derivation strictement deterministe
  • Phrase BIP-39 compatible avec standards industrie (wallets, etc.)
  • Envelope portable entre iOS/Android/Web (future story)
  • Vecteurs de test BIP-39 officiels valides

Observabilite (sans compromettre ZK)

Le backend peut tracer les evenements suivants (sans materiel sensible) :

Evenement Donnees tracees
recovery.envelope.created user_id, timestamp, envelope_hash
recovery.restore.attempt user_id, timestamp, success: boolean
recovery.restore.success user_id, timestamp, device_id
recovery.restore.failed user_id, timestamp, failure_reason
recovery.envelope.regenerated user_id, timestamp
recovery.rate_limit.exceeded user_id ou IP, timestamp

Contraintes

  • Execution exclusivement cote client pour la cryptographie
  • Bibliotheque BIP-39 auditee et maintenue (ex: bip39 npm)
  • Bibliotheque SHA3 conforme FIPS 202 (ex: js-sha3)
  • Aucun fallback vers des algorithmes moins securises
  • Aucun calcul cryptographique deporte (backend, HSM) sauf stockage envelope
  • Compatible Hermes (React Native) — pas de WebAssembly requis
  • Effacement memoire best-effort (JavaScript strings immutables)

Hypotheses

  • user_id est un UUID v4 stable disponible localement
  • Le Keychain iOS est accessible (PD-98 DONE)
  • Le backend dispose d'un endpoint REST pour stocker/recuperer l'envelope
  • L'utilisateur comprend l'importance de sauvegarder sa phrase de maniere securisee
  • Les bibliotheques cryptographiques utilisees sont auditees
  • Les operations crypto ne bloquent pas le thread UI (async)

Invariants de securite

ID Invariant Type Testable
INV-242-01 K_recovery ne transite JAMAIS en clair sur le reseau SEC Oui — capture reseau
INV-242-02 La phrase de recuperation n'est JAMAIS stockee (ni local, ni backend) SEC Oui — audit stockage
INV-242-03 K_recovery est detruite en memoire apres usage SEC Partiel — best-effort
INV-242-04 Le backend ne peut PAS dechiffrer K_master_user SEC Oui — analyse code
INV-242-05 L'entropie de la phrase est de 256 bits minimum SEC Oui — vecteurs BIP-39
INV-242-06 La derivation utilise HKDF-SHA3-256 avec domain separation CRYPTO Oui — vecteurs
INV-242-07 Le chiffrement de l'enveloppe utilise AES-256-GCM (AEAD) CRYPTO Oui — vecteurs
INV-242-08 La verification de phrase utilise un hash sans exposer K_recovery SEC Oui — analyse flux
INV-242-09 L'onboarding EXIGE la confirmation complete des 24 mots UX Oui — test E2E
INV-242-10 Un changement de device DECLENCHE automatiquement le flux recovery ARCH Oui — test E2E
INV-242-11 L'affichage phrase est protege contre les screenshots SEC Oui — test iOS
INV-242-12 L'affichage phrase expire apres 120 secondes SEC Oui — test timer
INV-242-13 Le rate limiting bloque apres 5 echecs / 15 min SEC Oui — test API

Tests d'acceptation

TA-1 — Validite BIP-39

La phrase generee est valide BIP-39 : - 24 mots exactement - Chaque mot appartient a la wordlist BIP-39 English - Checksum correct (8 bits SHA-256)

TA-2 — Determinisme derivation

A phrase identique et user_id identique, K_recovery est strictement identique (bit-a-bit). Verification via vecteurs de test avec valeurs attendues precalculees.

TA-3 — Chiffrement/dechiffrement round-trip

L'envelope peut etre dechiffree avec la phrase originale : 1. Generer phrase → deriver K_recovery → chiffrer K_master → obtenir envelope 2. Deriver K_recovery (meme phrase) → dechiffrer envelope → obtenir K_master 3. K_master originale === K_master dechiffree

TA-4 — Rejet phrase incorrecte

Une phrase incorrecte (1 mot different) ne permet PAS de dechiffrer l'envelope : - H_verify ne matche pas → restauration bloquee avant dechiffrement - Meme si bypass H_verify, AEAD echoue (tag invalide)

TA-5 — Verification pre-dechiffrement

H_verify permet de detecter une phrase incorrecte AVANT de tenter le dechiffrement : 1. Deriver K_recovery (phrase incorrecte) 2. Calculer H_verify_candidate 3. Comparer avec H_verify backend 4. Mismatch → erreur sans tenter dechiffrement

TA-6 — Absence de logs sensibles

K_recovery n'apparait dans aucun log applicatif : - Console.log - Crashlytics / Sentry - Analytics - Network logs - Exception stacktraces

TA-7 — Re-saisie obligatoire onboarding

L'onboarding ne peut pas se terminer sans re-saisie complete des 24 mots : - Skip impossible - Validation partielle impossible - Fermeture app → reprise depuis re-saisie

TA-8 — Flux recovery E2E

Le flux recovery restaure K_master sur un device vierge : 1. Device A : creer compte → sauvegarder phrase 2. Device B (vierge) : installer app → "Recuperer mon coffre" 3. Saisir phrase → K_master restauree → acces coffre OK

TA-9 — Invalidation ancienne envelope

La regeneration invalide l'ancienne envelope : 1. Generer phrase A → envelope A stockee backend 2. Regenerer phrase B → envelope B stockee backend 3. Phrase A ne fonctionne PLUS (H_verify mismatch) 4. Phrase B fonctionne

TA-10 — Performance

Les operations crypto n'excedent pas 3 secondes sur iPhone 12+ : - Generation phrase : < 100ms - Derivation K_recovery : < 500ms - Chiffrement envelope : < 100ms - Dechiffrement envelope : < 100ms - Verification H_verify : < 50ms

TA-11 — Protection screenshot

L'ecran d'affichage de la phrase est protege contre les screenshots : - secureTextEntry ou equivalent iOS - FLAG_SECURE equivalent - Screenshot capture une image vide ou masquee

TA-12 — Timeout affichage

L'affichage de la phrase se masque automatiquement apres 120 secondes : - Countdown visible - Masquage automatique (phrase remplacee par astérisques ou écran vide) - Utilisateur peut re-afficher (avec authentification)

TA-13 — Rate limiting restauration

Apres 5 tentatives echouees, le rate limiting bloque : - 6eme tentative → erreur 429 - Attendre 15 minutes → tentatives restaurees

TA-14 — Vecteurs BIP-39 officiels

Les vecteurs de test BIP-39 officiels (TREZOR) passent : - Mnemonic → seed correct - Validation checksum - Rejection mots invalides

TA-15 — Portabilite envelope

L'envelope generee sur iOS est dechiffrable par les memes primitives sur Android/Web : - Pas de format proprietaire - Nonce inclus dans le ciphertext (standard) - Tag authentification 128 bits en suffixe

TA-16 — Observabilite backend

Les evenements de recovery sont traces cote backend : - recovery.envelope.created au premier setup - recovery.restore.attempt a chaque tentative - recovery.restore.success ou failed selon resultat

Livrables

  • Module RecoveryService dans le package crypto client iOS
  • Fonction generateMnemonic() → string[]
  • Fonction deriveRecoveryKey(mnemonic, userId) → Uint8Array
  • Fonction createRecoveryEnvelope(K_recovery, K_master) → { envelope, nonce, tag }
  • Fonction restoreFromEnvelope(K_recovery, envelope) → K_master
  • Fonction computeVerificationHash(K_recovery, userId) → Uint8Array
  • Ecran de creation recovery (onboarding)
  • Ecran de restauration recovery
  • Ecran de regeneration recovery
  • Tests unitaires avec vecteurs
  • Tests E2E des 3 flux
  • Documentation /docs/crypto/recovery-envelope.md

API Backend (specification)

POST /recovery/envelope

Stocke la recovery envelope.

Request:

{
  "user_id": "uuid",
  "envelope": "base64",
  "h_verify": "base64"
}

Response: 201 Created

GET /recovery/h_verify/:user_id

Recupere le hash de verification.

Response:

{
  "h_verify": "base64"
}

GET /recovery/envelope/:user_id

Recupere la recovery envelope (apres verification H_verify reussie).

Headers requis: X-H-Verify-Candidate: base64

Response:

{
  "envelope": "base64"
}

Erreurs: - 401 si X-H-Verify-Candidate mismatch - 429 si rate limit exceeded

DELETE /recovery/envelope/:user_id

Invalide l'envelope existante (appele avant regeneration).

Auth: Bearer token + biometric proof

Response: 204 No Content

Liens documentaires

  • Architecture technique v4.1 (doc 42) — Section Recovery Envelope
  • Specifications techniques v2.1 (doc 43) — HKDF, AES-GCM
  • BIP-0039 : Mnemonic code for generating deterministic keys
  • RFC 5869 : HMAC-based Extract-and-Expand Key Derivation Function
  • FIPS 202 : SHA-3 Standard
  • NIST SP 800-38D : Recommendation for Block Cipher Modes of Operation: GCM
  • PD-97 : Pipeline crypto zero-knowledge iOS
  • PD-98 : Stockage K_master dans Keychain iOS

Definition of Done

  • Implementation conforme aux parametres cryptographiques normatifs
  • Tests unitaires avec vecteurs BIP-39 officiels validés
  • Tests E2E des 3 flux (creation, restauration, regeneration)
  • Test de performance < 3s sur iPhone 12+
  • Test protection screenshot
  • Test timeout affichage
  • Test rate limiting
  • Aucun log ou fuite de secret (audit console + Sentry)
  • Documentation publiee
  • Revue securite validee
  • Code review approuvee
  • Pipeline CI/CD vert