Aller au contenu

PD-24 — Authentification SRP-6a (Phase 1)


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

Références

  • EPIC : PD-189 — CRYPTO
  • JIRA : PD-24
  • Normes : RFC 5054 (SRP-6a), SHA3-256
  • Dépendances crypto : Argon2id (pré-traitement mot de passe)

Objectif

Implémenter la Phase 1 du protocole SRP-6a dans le cadre du socle cryptographique ProbatioVault, afin de garantir une authentification strictement zero-knowledge :

  • le mot de passe utilisateur ne transite jamais vers le backend ;
  • aucun secret exploitable n'est stocké côté serveur ;
  • l'authentification repose exclusivement sur des preuves cryptographiques.

Cette User Story met en place l'initialisation complète du protocole SRP et prépare les éléments nécessaires à la Phase 2 (calcul du secret partagé et preuves mutuelles).

Description fonctionnelle

La Phase 1 du protocole SRP-6a couvre deux moments distincts :

À l'inscription

  • Le client dérive localement un verifier cryptographique à partir du mot de passe utilisateur.
  • Le serveur reçoit et stocke uniquement :
  • un salt utilisateur ;
  • un verifier SRP.
  • Aucun élément ne permet au serveur de reconstituer le mot de passe.

À la connexion (initialisation SRP)

  • Le client initie l'authentification sans révéler le mot de passe.
  • Le serveur génère un secret éphémère et retourne un challenge public.
  • Les deux parties valident cryptographiquement les paramètres échangés.
  • Les éléments nécessaires à la Phase 2 sont préparés, sans encore calculer le secret partagé.

Diagrammes de flux

Inscription

┌─────────────────────────────────────────────────────────────────────────────┐
│                              INSCRIPTION                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Client (React Native)                        Serveur (NestJS)               │
│  ────────────────────                         ────────────────               │
│                                                                              │
│  1. salt = random(16 bytes)                                                  │
│  2. K_auth = Argon2id(password, salt,                                        │
│              "ProbatioVault_SRP_Auth_v1")                                    │
│  3. x = SHA3-256(salt || K_auth)                                             │
│  4. verifier = g^x mod N                                                     │
│                                                                              │
│         ────── POST /auth/register ──────>                                   │
│                {email, salt, verifier}                                       │
│                                               5. Valide salt (16-32 bytes)   │
│                                               6. Valide verifier ∈ [1, N-1]  │
│                                               7. Stocke {email, salt, v}     │
│         <────── 201 Created ──────────────                                   │
│                {userId}                                                      │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Authentification (Phase 1 - Challenge)

┌─────────────────────────────────────────────────────────────────────────────┐
│                     AUTHENTIFICATION - Phase 1 Challenge                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Client                                       Serveur                        │
│  ──────                                       ───────                        │
│                                                                              │
│  1. a = random(256 bits)     [SECRET]                                        │
│  2. A = g^a mod N                                                            │
│                                                                              │
│         ────── POST /auth/login/challenge ──>                                │
│                {email, A}                                                    │
│                                               3. Valide A mod N ≠ 0          │
│                                               4. Récupère {salt, v} du user  │
│                                               5. b = random(256 bits)        │
│                                               6. B = k*v + g^b mod N         │
│                                               7. Stocke session {A,b,B,v}    │
│         <────── {salt, B} ───────────────────                                │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Diagrammes Mermaid

Séquence — Inscription Zero-Knowledge

Ce diagramme détaille l'échange client-serveur à l'inscription. Les validations serveur (salt 16-32 bytes, verifier dans [1, N-1]) garantissent qu'aucun paramètre dégénéré n'est accepté (cf. Contraintes de validation).

sequenceDiagram
    participant C as Client (React Native)
    participant S as Serveur (NestJS)

    Note over C: salt = random(16 bytes)
    Note over C: K_auth = Argon2id(password, salt,<br/>"ProbatioVault_SRP_Auth_v1")
    Note over C: x = SHA3-256(salt || K_auth)
    Note over C: verifier = g^x mod N

    C->>S: POST /auth/register {email, salt, verifier, plan}

    Note over S: Valide salt (16-32 bytes hex)
    Note over S: Valide verifier ∈ [1, N-1]
    Note over S: Stocke {email, salt, verifier}

    S-->>C: 201 Created {userId}

    Note over C,S: INV: le mot de passe ne transite jamais (Zero-Knowledge)
    Note over C,S: INV: le serveur ne stocke ni password, ni x, ni K_auth

Séquence — Authentification Phase 1 (Challenge SRP-6a)

Ce diagramme détaille l'échange challenge-response de la Phase 1. Les validations A mod N != 0 et B mod N != 0 empêchent les attaques par paramètre nul (cf. Sécurité cryptographique).

sequenceDiagram
    participant C as Client
    participant S as Serveur

    Note over C: a = random(≥256 bits) [SECRET]
    Note over C: A = g^a mod N

    C->>S: POST /auth/login/challenge {email, A}

    Note over S: Valide A mod N ≠ 0
    Note over S: Récupère {salt, verifier} du user
    Note over S: b = random(≥256 bits) [SECRET]
    Note over S: B = k*v + g^b mod N
    Note over S: Stocke session SRP {A, b, B, v}

    S-->>C: 200 OK {salt, B}

    Note over C: Valide B mod N ≠ 0
    Note over C: u = SHA3-256(A || B)
    Note over C: Valide u ≠ 0

    Note over C,S: INV: secrets éphémères (a, b) ≥ 256 bits CSPRNG
    Note over C,S: INV: rejet immédiat si A mod N = 0 ou B mod N = 0 ou u = 0
    Note over C,S: INV: session SRP à usage unique, TTL 5 min

État — Session SRP éphémère

La session SRP côté serveur traverse 4 états. Le TTL de 5 minutes et le caractère single-use protègent contre le replay (cf. Sécurité — Session hijacking).

stateDiagram-v2
    [*] --> CREATED : POST /auth/login/challenge<br/>A valide (A mod N ≠ 0)

    CREATED --> VERIFIED : Phase 2 — M1 valide (PD-25)
    CREATED --> EXPIRED : TTL 5 min dépassé
    CREATED --> REJECTED : A mod N = 0<br/>ou u = 0<br/>ou M1 invalide

    VERIFIED --> CONSUMED : Session key émise (PD-25)
    VERIFIED --> [*]

    EXPIRED --> [*]
    REJECTED --> [*]
    CONSUMED --> [*]

    note right of CREATED
        Stocke {A, b, B, v}
        Usage unique (single-use)
        INV: effacement mémoire best-effort
        des secrets éphémères après consommation
    end note

    note right of EXPIRED
        Nettoyage automatique
        par job de purge
    end note

API Endpoints

GET /auth/srp-params

Récupère les paramètres publics SRP.

Response 200:

{
  "N": "FFFFFFFFFFFFFFFFC90FDAA22168C234...",
  "g": "2"
}

POST /auth/register

Inscription Zero-Knowledge.

Request:

{
  "email": "user@example.com",
  "salt": "a1b2c3d4e5f6...",
  "verifier": "f6e5d4c3b2a1...",
  "plan": "free"
}

Response 201:

{
  "message": "Utilisateur enregistré avec succès",
  "userId": "123e4567-e89b-12d3-a456-426614174000"
}

POST /auth/login/challenge

Phase 1 : Initialise le challenge SRP.

Request:

{
  "email": "user@example.com",
  "A": "a1b2c3d4e5f6..."
}

Response 200:

{
  "salt": "a1b2c3d4e5f6...",
  "B": "f6e5d4c3b2a1..."
}

Périmètre

Inclus

  • Génération client-side du salt et du verifier SRP à l'inscription.
  • Stockage serveur sécurisé du salt et du verifier.
  • Initialisation du protocole SRP-6a à la connexion :
  • génération de A côté client ;
  • génération de B côté serveur ;
  • calcul et validation de u.
  • Validation cryptographique stricte des paramètres échangés.
  • API d'initialisation SRP.
  • Tests de conformité et de sécurité.

Exclu

  • Phase 2 SRP-6a (calcul du secret partagé, preuves M1/M2, génération de session).
  • Émission de JWT ou gestion de session.
  • MFA, refresh tokens, rotation de clés.
  • Chiffrement client-side des données.
  • Gestion HSM ou audit probatoire.

Paramètres cryptographiques normatifs

Les paramètres suivants sont obligatoires et non négociables :

Groupe SRP

Élément Valeur
Groupe Safe Prime 3072 bits (RFC 5054 Group 15)
Référence RFC 5054 — Appendix A (group 15)
Générateur g = 2

Fonctions de hash

Usage Algorithme
Hash SRP SHA3-256
k = H(N \ \
u = H(A \ \

Secrets éphémères

  • a (client) : ≥ 256 bits aléatoires
  • b (serveur) : ≥ 256 bits aléatoires

Pré-traitement mot de passe

Avant SRP :

  • Le mot de passe est dérivé via Argon2id.
  • La valeur résultante est intégrée dans le calcul de x.

Propriétés attendues

Zero-Knowledge

  • Le mot de passe utilisateur ne quitte jamais le client.
  • Le serveur ne stocke jamais :
  • le mot de passe ;
  • x ;
  • A, S, M1, M2.
  • Les échanges réseau ne permettent aucune attaque par dictionnaire offline.

Sécurité cryptographique

  • Validation stricte :
  • A mod N ≠ 0
  • B mod N ≠ 0
  • u ≠ 0
  • Rejet immédiat en cas de paramètre invalide.
  • Effacement mémoire best-effort des secrets éphémères.

Interopérabilité

  • Implémentation conforme RFC 5054.
  • Résultats déterministes et reproductibles.
  • Compatible avec la Phase 2 (PD-25).

Sécurité

Protections implémentées

Attaque Protection
Interception réseau Le password ne transite jamais
Base de données compromise Le verifier ne permet pas de retrouver le password
Replay attack Éphémères uniques par session
Man-in-the-middle Authentification mutuelle (M1/M2 en Phase 2)
A = 0 attack Validation A mod N ≠ 0
Timing attack Délai aléatoire côté serveur
Session hijacking Sessions SRP à usage unique, TTL 5 min
Brute force offline Argon2id memory-hard (64 MiB)

Contraintes de validation

Paramètre Contrainte
Salt 16-32 bytes, hexadécimal
Verifier 1 < v < N, hexadécimal
A A mod N ≠ 0, hexadécimal
M1 64 caractères hex (32 bytes)
Password Min 12 caractères (prod), 4 (dev)

Contraintes

  • Implémentation strictement conforme SRP-6a.
  • Aucun fallback vers un schéma d'authentification plus faible.
  • Aucun log de données sensibles.
  • Limitation des tentatives et protection DoS.
  • Timeout des échanges SRP incomplets.

Hypothèses

  • Le client dispose d'un générateur CSPRNG fiable.
  • Les paramètres SRP sont figés et partagés par toutes les plateformes.
  • Le backend peut maintenir un état temporaire de session SRP.
  • La Phase 2 est implémentée séparément.

Tests d'acceptation

TA-1 — Inscription SRP

  • Le serveur stocke uniquement salt et verifier.
  • Aucune donnée sensible n'est persistée.

TA-2 — Initialisation SRP

  • Le serveur retourne { salt, B }. Les paramètres publics N et g sont fournis via GET /auth/srp-params (constants RFC 5054) et ne sont pas renvoyés dans chaque challenge.
  • B mod N ≠ 0.

TA-3 — Génération client de A

  • A mod N ≠ 0.
  • Aucune fuite du secret a.

TA-4 — Calcul de u

  • u = H(A || B) calculé correctement.
  • Rejet si u = 0.

TA-5 — Zero-Knowledge

  • Inspection réseau :
  • aucun mot de passe ;
  • aucun dérivé Argon2id ;
  • aucun secret SRP.

TA-6 — Conformité RFC

  • Calculs conformes aux vectors SRP officiels.
  • Groupe N=3072 bits (RFC 5054 Group 15) strictement respecté.

TA-7 — Préparation Phase 2

  • Le serveur dispose de tous les éléments nécessaires pour enchaîner immédiatement vers PD-25.

Livrables

  • Implémentation client SRP Phase 1.
  • Implémentation backend SRP Phase 1.
  • Tests unitaires cryptographiques.
  • Documentation /docs/auth/srp/phase1/.
  • Rapport de conformité sécurité.

Liens documentaires

  • EPIC : PD-189 — CRYPTO
  • RFC 5054 — Secure Remote Password
  • Architecture Zero-Knowledge ProbatioVault
  • PD-25 — SRP-6a Phase 2

Definition of Done

  • Flux SRP Phase 1 fonctionnel.
  • Paramètres cryptographiques conformes.
  • Zero-knowledge vérifié.
  • Tests unitaires et d'intégration validés.
  • Documentation publiée.
  • Revue sécurité approuvée.