RFC PV-ENV-001 : ProbatioVault Envelope Protocol¶
Statut : Proposition interne Version : 1.4.0 Date : 2026-03-02 Auteur : ProbatioVault Engineering Verification formelle : TLA+ (TLC), Alloy (SAT), Z Notation, Prolog Changelog : v1.4 — ENV-26/27 encodages binaires HKDF (RFC 5869 + SHA-256), ENV-17 metadata_tag HMAC-SHA256 exact, ENV-28 profil Argon2id versionne, ENV-29 BIP-39 wordlist anglaise figee, ENV-14 generation K_master CSPRNG 256 bits, ENV-30 documentation zeroization runtime
1. Introduction¶
1.1 Objectif¶
Ce document specifie le protocole PV Envelope, un systeme de gestion de cles hierarchique zero-knowledge pour le chiffrement cote client des documents et metadonnees stockes dans ProbatioVault.
Le serveur ne possede jamais les cles en clair. L'utilisateur controle l'integralite de la hierarchie de cles a partir de son mot de passe.
1.2 Portee¶
Ce protocole couvre :
- La derivation de la cle maitre (K_master) a partir du mot de passe utilisateur
- L'enveloppement (wrapping) de K_master dans des enveloppes chiffrees
- La derivation de cles applicatives (partage, document, recherche chiffree)
- La gestion multi-device et la revocation
- La rotation des enveloppes avec metadata binding et audit trail
- Le nettoyage memoire (zeroization) adapte au runtime
- La recovery via BIP-39 mnemonic
1.3 References normatives¶
| Reference | Titre | Usage |
|---|---|---|
| RFC 9106 | Argon2 Memory-Hard Function | Derivation mot de passe -> K_enc |
| RFC 3394 | AES Key Wrap Algorithm | Enveloppement K_master |
| RFC 5869 | HMAC-based Extract-and-Expand KDF | Derivation K_share, K_doc, K_search |
| BIP-39 | Mnemonic code for generating deterministic keys | Recovery envelope |
| NIST SP 800-131A | Transitions: Recommendation for Key Lengths | Tailles de cles minimum |
1.4 Terminologie¶
| Terme | Definition |
|---|---|
| K_master | Cle maitre de l'utilisateur (256 bits). Ne quitte jamais la memoire en clair. |
| K_enc | Cle de chiffrement derivee du mot de passe via Argon2id. Sert uniquement a envelopper K_master. |
| Envelope | Structure contenant K_master enveloppe (wrapping AES-KW). Trois types : MASTER, DEVICE, RECOVERY. |
| K_share | Cle derivee de K_master via HKDF, contexte share, salt fixe par utilisateur (user_salt). Chiffrement au niveau utilisateur. |
| K_doc | Cle derivee de K_master via HKDF, contexte doc, salt = documentId. Chiffrement par document (une cle unique par document). |
| K_search | Cle derivee de K_master via HKDF, contexte search, salt fixe par utilisateur (user_salt). Recherche chiffree deterministe : pour un meme (K_master, user_salt), produit toujours la meme cle (voir section 5.3). |
| user_salt | Sel unique par utilisateur (>= 16 bytes, CSPRNG). Genere une fois a l'inscription, immuable. Stocke en clair cote serveur (meme modele que le sel Argon2). Utilise comme salt HKDF pour K_share et K_search. |
| Metadata tag | HMAC lie a l'envelope et a son contexte client, garantissant l'integrite des metadonnees (section 3.7). Verifie exclusivement cote client au unwrap. |
| Zeroization | Effacement cryptographique d'une cle en memoire, adapte au runtime (voir section 3.9). |
2. Vue d'ensemble du protocole¶
2.1 Hierarchie de cles¶
Password (utilisateur)
|
| Argon2id (RFC 9106)
| type=2, memory>=64 MiB, passes>=3
| salt>=16 bytes (CSPRNG), output=32 bytes
v
K_enc (256 bits, ephemere)
|
| AES-KW (RFC 3394)
| wrapping: 32 bytes -> 40 bytes (32 + 8 IV)
v
+-------------------+-------------------+-------------------+
| MASTER envelope | DEVICE envelope | RECOVERY envelope |
| (password-based) | (device-bound) | (BIP-39 24 mots) |
+-------------------+-------------------+-------------------+
| | |
+-----------+-----------+-----------+-----------+
|
v
K_master (256 bits, persistant)
|
| HKDF (RFC 5869)
|
+-----------+-----------+-----------+
| | | |
v v v |
K_share K_doc_i K_search |
(256 bits) (256 bits) (256 bits) |
salt=user salt=docId salt=user |
| | | |
v v v |
Chiffrement Chiffrement Recherche |
utilisateur par document chiffree |
2.2 Flux de donnees¶
- Inscription :
Password -> Argon2id -> K_enc -> AES-KW(K_enc, K_master) -> MASTER envelope + metadata_tag - Connexion :
Password -> Argon2id -> K_enc -> AES-KW-unwrap(MASTER envelope) -> K_master - Multi-device :
K_device -> AES-KW(K_device, K_master) -> DEVICE envelope - Derivation K_share/K_search :
HKDF(K_master, salt=user_salt, info=ctx) -> K_share | K_search - Derivation K_doc :
HKDF(K_master, salt=documentId, info="pv-doc-v1") -> K_doc_i(une cle par document) - Recovery :
BIP-39(24 mots) -> PBKDF2 -> K_recovery -> AES-KW(K_recovery, K_master) -> RECOVERY envelope - Rotation :
unwrap(ancien) -> K_master -> wrap(nouveau K_enc) -> nouveau envelope + metadata_tag + audit event
3. Specifications detaillees¶
3.1 Derivation du mot de passe (Argon2id)¶
La derivation du mot de passe vers K_enc utilise Argon2id (RFC 9106 type 2) :
| Parametre | Valeur minimum RFC | Valeur ProbatioVault | Justification |
|---|---|---|---|
type | 2 (Argon2id) | 2 (Argon2id) | Resistance GPU + side-channel |
memory | >= 8 * parallelism | >= 65536 KiB (64 MiB) | Recommandation OWASP 2024 |
passes | >= 1 (RFC 9106 §4) | >= 3 | Durcissement iteratif ProbatioVault |
parallelism | >= 1 | >= 1 | Adaptation hardware |
salt | >= 16 bytes | >= 16 bytes, CSPRNG | Prevention rainbow tables |
hashLength | variable | 32 bytes (256 bits) | Taille K_enc |
Note : Le RFC 9106 §4 impose
passes >= 1comme minimum. ProbatioVault durci apasses >= 3pour un profil plus resistant. Les deux valeurs (minimum RFC et profil ProbatioVault) sont distinguees dans les modeles formels.
EXIGENCE ENV-01 : Le parametre type DOIT etre 2 (Argon2id). Les variantes Argon2d (type 0) et Argon2i (type 1) sont INTERDITES.
EXIGENCE ENV-02 : Le sel DOIT etre genere par un CSPRNG (ex: crypto.getRandomValues()). Le sel DOIT etre stocke en clair a cote de l'envelope.
EXIGENCE ENV-03 : Les parametres Argon2 DOIVENT etre stockes dans l'envelope pour permettre la re-derivation. Un changement de parametres implique une rotation d'envelope.
EXIGENCE ENV-28 : Le profil Argon2id est versionne. Le profil actuel est "PV-ARGON2-P1" : - type=2, memory=65536 KiB, passes=3, parallelism=1, hashLength=32, salt>=16 bytes
L'identifiant de profil est stocke dans l'envelope (champ argon2Profile). Un changement de profil implique une rotation d'envelope. L'implementation DOIT accepter les envelopes generees avec un profil anterieur (retrocompatibilite en lecture). Les nouveaux wraps DOIVENT utiliser le profil courant.
3.2 Enveloppement AES-KW (RFC 3394)¶
L'enveloppement de K_master utilise AES Key Wrap :
| Propriete | Valeur |
|---|---|
| Algorithme | AES-256-KW |
| Entree (plaintext) | 32 bytes (K_master) |
| Sortie (ciphertext) | 40 bytes (32 + 8 bytes IV) |
| Verification d'integrite | Integree dans RFC 3394 (IV check au unwrap) |
EXIGENCE ENV-04 : Le ciphertext enveloppe DOIT avoir une taille de 40 bytes. Toute taille differente indique une erreur d'implementation.
EXIGENCE ENV-05 : L'operation unwrap(wrap(K_master)) DOIT retourner K_master identique (propriete roundtrip). Cet invariant est verifie formellement (INV-03).
EXIGENCE ENV-06 : Apres unwrap, K_enc DOIT etre immediatement zeroize de la memoire (voir section 3.9 pour les mecanismes par runtime).
3.3 Derivation HKDF (RFC 5869)¶
La derivation de cles applicatives utilise HKDF en mode extract-then-expand :
| Derivation | IKM | Salt | Info (contexte) | OKM |
|---|---|---|---|---|
| K_share | K_master | user_salt (fixe par utilisateur) | "pv-share-v1" | 32 bytes |
| K_doc_i | K_master | documentId (unique par document) | "pv-doc-v1" | 32 bytes |
| K_search | K_master | user_salt (fixe par utilisateur) | "pv-search-v1" | 32 bytes |
EXIGENCE ENV-07 : Deux contextes DIFFERENTS avec le meme salt DOIVENT produire des cles DIFFERENTES (isolation par contexte). Prouve formellement (TLA+ INV-06, Alloy ContextSeparation, Z INV-06).
EXIGENCE ENV-07b : Pour K_doc, deux documentIds DIFFERENTS avec le meme contexte DOIVENT produire des cles DIFFERENTES (isolation par salt). Prouve formellement (TLA+ INV-09 DocKeyIsolation, Alloy SaltSeparation, Z INV-11).
EXIGENCE ENV-08 : Le meme triplet (K_master, contexte, salt) DOIT toujours produire la meme cle derivee (determinisme). Prouve par Alloy KeyIsolation.
EXIGENCE ENV-26 : L'algorithme HKDF utilise HMAC-SHA256 (RFC 5869 avec SHA-256) pour toutes les derivations (K_share, K_doc, K_search, K_recovery). L'utilisation de SHA-512 ou d'autres fonctions de hash est INTERDITE pour les derivations HKDF de ce protocole.
EXIGENCE ENV-27 : Les entrees HKDF sont encodees comme suit : - IKM : K_master, 32 bytes bruts - Salt : octets bruts du salt (user_salt = 16+ bytes CSPRNG, documentId = 16 bytes UUID RFC 4122 en representation binaire big-endian) - Info : chaine ASCII sans terminateur null ("pv-share-v1", "pv-doc-v1", "pv-search-v1", "pv-recovery-v1") - OKM : 32 bytes (256 bits)
EXIGENCE ENV-25 : Le user_salt utilise pour K_share et K_search DOIT etre :
= 16 bytes, genere par un CSPRNG
- Genere une seule fois a l'inscription de l'utilisateur, immuable apres creation
- Stocke en clair cote serveur (meme modele que le sel Argon2)
- Unique par utilisateur (pas de reutilisation inter-utilisateurs)
3.4 Types d'enveloppes¶
Trois types d'enveloppes existent pour un meme K_master :
| Type | Cle d'enveloppement | Usage | Stockage |
|---|---|---|---|
| MASTER | K_enc (Argon2id du password) | Connexion standard | Serveur |
| DEVICE | K_device (specifique a l'appareil) | Multi-device | Serveur + device |
| RECOVERY | K_recovery (BIP-39 mnemonic, voir section 3.8) | Recuperation | Serveur |
EXIGENCE ENV-09 : Chaque utilisateur DOIT avoir exactement un (1) envelope de type MASTER. Prouve formellement (TLA+ INV-02, Alloy OneMasterPerUser).
EXIGENCE ENV-10 : Un device revoque (blackliste) NE DOIT PAS avoir d'envelope active. Prouve formellement (TLA+ INV-04, Alloy BlacklistEnforced).
3.5 Versioning des enveloppes¶
EXIGENCE ENV-11 : Chaque envelope possede un compteur de version. La version initiale est 1. Chaque rotation incremente la version de 1.
EXIGENCE ENV-12 : La version est STRICTEMENT croissante (monotone). Prouve formellement (TLA+ INV-05, Alloy VersionPositive).
3.6 Rotation d'enveloppe¶
La rotation permet de changer la cle d'enveloppement (ex: changement de mot de passe) SANS changer K_master.
Procedure :
- Unwrap K_master avec l'ancien K_enc
- Deriver le nouveau K_enc (Argon2id du nouveau mot de passe)
- Wrap K_master avec le nouveau K_enc
- Incrementer la version
- Calculer le nouveau metadata_tag (section 3.7)
- Emettre un evenement d'audit ROTATE (section 3.10)
- Zeroizer l'ancien K_enc et le nouveau K_enc
EXIGENCE ENV-13 : Apres rotation, K_master DOIT etre identique. Prouve formellement (TLA+ INV-03 RoundtripInvariant).
3.7 Metadata binding¶
Chaque envelope DOIT etre liee a ses metadonnees par un tag d'integrite, verifie cote client au moment du unwrap.
EXIGENCE ENV-17 : Chaque envelope possede un metadata_tag calcule avec HMAC-SHA256 :
ou canonical_binding est la concatenation sans separateur des champs suivants, dans cet ordre : - uid : UUID 16 bytes binaire (RFC 4122, big-endian) - envelope_id : UUID 16 bytes binaire - version : uint32 big-endian (4 bytes) - envelope_type : 1 byte (0x01=MASTER, 0x02=DEVICE, 0x03=RECOVERY) - algorithm : chaine ASCII longueur-prefixee (1 byte longueur + contenu, ex: 0x09 + "AES256-KW") - argon2_salt : octets bruts (16+ bytes)
Le binding DOIT couvrir au minimum :
- Un identifiant stable de l'owner (
uid) — empeche le swap inter-utilisateurs - Un identifiant de l'envelope (
envelope_id) — empeche le swap inter-envelopes - La version et le type — empeche le rollback et la confusion de type
Note architecturale : K_enc est derive du mot de passe, donc le serveur ne peut PAS verifier le tag. La verification se fait exclusivement cote client, au moment du unwrap. Cela signifie qu'un tampering des metadonnees cote serveur ne sera detecte qu'a la prochaine connexion de l'utilisateur. Cette limitation est inherente au modele zero-knowledge.
EXIGENCE ENV-18 : Le metadata_tag DOIT etre non-nul pour toute envelope existante. Prouve formellement (TLA+ INV-10 MetadataBinding, Alloy MetadataBindingValid, Z INV-12).
EXIGENCE ENV-19 : Lors d'une rotation, le metadata_tag DOIT etre recalcule avec la nouvelle version. Prouve formellement (Z THM-08).
3.8 Recovery BIP-39¶
L'envelope RECOVERY utilise un mnemonic BIP-39 comme source de la cle d'enveloppement.
Pipeline :
- Generer 256 bits d'entropie via CSPRNG
- Calculer le checksum (8 bits pour 256 bits d'entropie)
- Encoder en 24 mots selon la wordlist BIP-39
- Deriver le seed BIP-39 via PBKDF2(mnemonic, passphrase="", 2048 iterations, HMAC-SHA512) -> 64 bytes
- Deriver K_recovery (32 bytes) via HKDF-SHA256(IKM=seed_64, salt="", info="pv-recovery-v1", L=32)
- Wrap K_master avec K_recovery via AES-256-KW
Note : PBKDF2-HMAC-SHA512 (BIP-39 §5) produit un seed de 64 bytes. AES-256-KW requiert une cle de 32 bytes. La derivation HKDF intermediaire (etape 5) est obligatoire pour garantir l'interoperabilite. La troncature brute du seed est INTERDITE.
EXIGENCE ENV-20 : L'envelope RECOVERY DOIT utiliser un mnemonic de 24 mots (256 bits d'entropie). Les mnemonics de 12 mots (128 bits) sont INTERDITS pour ProbatioVault.
EXIGENCE ENV-29 : La wordlist BIP-39 utilisee est exclusivement la wordlist anglaise (2048 mots, SHA-256 checksum 2f5eed53a4727b4bf8880d8f3f199d68ad0e19914c3e15805b2e9b093793e7d6). Les wordlists dans d'autres langues sont INTERDITES pour ProbatioVault.
EXIGENCE ENV-21 : Le mnemonic NE DOIT JAMAIS etre stocke sur le serveur. Il DOIT etre presente a l'utilisateur une seule fois pour sauvegarde hors-ligne.
EXIGENCE ENV-22 : Chaque envelope RECOVERY DOIT etre associee a un enregistrement BIP-39. Prouve formellement (Alloy RecoveryBIP39Present, Z schema BIP39Recovery).
3.9 Zeroization¶
EXIGENCE ENV-15 : Toute cle derivee en memoire (K_enc, K_share, K_doc, K_search) DOIT etre zeroizee apres usage. Seul K_master peut persister en memoire le temps de la session.
EXIGENCE ENV-16 : Une cle ne peut etre zeroizee que si elle a ete precedemment derivee. Prouve formellement (TLA+ INV-07 ZeroizeComplete).
Mecanismes par runtime :
| Runtime | Mecanisme de zeroization | Garantie |
|---|---|---|
| Node.js / V8 | buffer.fill(0) sur Buffer (hors GC pour les Buffers > 4 KiB). Limitation : pour les cles stockees dans des Uint8Array ou des strings JS, le GC peut copier la valeur. Utiliser crypto.subtle + ArrayBuffer + remplissage explicite. | Best-effort — pas de garantie formelle d'absence de copie GC |
| Rust / WASM | zeroize crate (impl Drop + Zeroize) | Garanti a la liberation |
| Swift (iOS) | Data.withUnsafeMutableBytes { $0.initializeMemory(as: UInt8.self, repeating: 0) } | Garanti si pas d'optimisation compilateur |
Caveat : En environnement JavaScript/V8, la zeroization est best-effort. Pour les cles a haute sensibilite (K_master), privilegier un module natif (N-API) ou WASM avec zeroize garanti.
3.10 Generation de K_master¶
EXIGENCE ENV-14 : K_master DOIT etre genere par un CSPRNG (crypto.getRandomValues ou equivalent) avec 256 bits d'entropie. La generation a lieu une seule fois, a l'inscription de l'utilisateur. K_master n'est jamais derive d'un mot de passe ni d'une autre cle. Le mot de passe sert uniquement a deriver K_enc, qui enveloppe K_master via AES-KW.
3.11 Documentation de la zeroization runtime¶
EXIGENCE ENV-30 : Pour les operations sur K_master (unwrap, rotation, derivation), l'implementation DOIT documenter le niveau de garantie de zeroization de son runtime. Si le runtime ne peut garantir l'absence de copie GC (cas JavaScript/V8), cette limitation DOIT etre documentee dans le rapport de securite du deploiement. Le rapport DOIT specifier : (a) le runtime utilise, (b) le mecanisme de zeroization employe, © les limitations connues, (d) les mesures compensatoires (ex: module N-API, WASM zeroize).
3.12 Audit trail (anti-rollback)¶
EXIGENCE ENV-23 : Chaque operation modifiant une envelope (creation, rotation, revocation) DOIT emettre un evenement d'audit append-only. Prouve formellement (TLA+ INV-11 AuditAppendOnly, Z THM-09).
EXIGENCE ENV-24 : L'audit log NE DOIT JAMAIS etre tronque ni supprime. Les evenements sont immutables. L'append-only DOIT etre garanti par un support offrant des proprietes d'immutabilite verifiable (ex: stockage WORM, chainage de hash, ancrage blockchain).
Evenements audites :
| Evenement | Declencheur | Donnees |
|---|---|---|
| CREATE | GenerateKMaster | uid, version=1, timestamp |
| ROTATE | RotateEnvelope | uid, new_version, timestamp |
| REVOKE | RevokeDevice | uid, device_id, timestamp |
4. Modele formel¶
4.1 Etats et transitions¶
Le protocole est modelise comme un systeme a etats avec 9 actions :
+----> CreateMasterEnvelope ---+
| |
GenerateKMaster ----+----> CreateDeviceEnvelope ---+----> DeriveUserKey ----> ZeroizeKey
| | |
| +----> CreateRecoveryEnvelope --+----> DeriveDocKey
| |
+-audit---> +----> RevokeDevice ----> audit
|
+----> RotateEnvelope ----> audit
| Action | Preconditions | Postconditions |
|---|---|---|
| GenerateKMaster(uid) | uid n'existe pas | K_master cree, envelope initialise, version=1, metadata_tag, audit CREATE |
| CreateMasterEnvelope(uid) | K_master existe, master=0 | master envelope enregistre (40 bytes) |
| CreateDeviceEnvelope(uid, devId) | master envelope existe, device pas blackliste | device ajoute aux envelopes |
| CreateRecoveryEnvelope(uid) | master existe, recovery=0 | recovery envelope enregistre |
| DeriveUserKey(uid, ctx) | K_master existe, ctx in {share, search}, paire non derivee | cle user-level derivee |
| DeriveDocKey(uid, docId) | K_master existe, paire (uid,docId) non derivee | cle doc derivee (salt=docId) |
| RevokeDevice(uid, devId) | device dans envelopes actifs | device blackliste, retire des actifs, audit REVOKE |
| RotateEnvelope(uid) | master existe | nouveau wrap, version++, metadata_tag, audit ROTATE |
| ZeroizeKey(uid, ctx) | cle derivee, pas encore zeroizee | cle marquee zeroizee |
4.2 Invariants de surete¶
Les proprietes suivantes sont verifiees par model checking :
| ID | Invariant | Description | Preuve |
|---|---|---|---|
| INV-01 | TypeInvariant | Types corrects pour toutes les variables | TLC |
| INV-02 | OneMasterPerUser | Exactement 1 master par utilisateur | TLC + Alloy |
| INV-03 | RoundtripInvariant | K_master inchange apres wrap/unwrap | TLC |
| INV-04 | BlacklistEnforced | Device blackliste exclu des actifs | TLC + Alloy |
| INV-05 | VersionMonotone | Version >= 1 et croissante | TLC + Alloy |
| INV-06 | KeyIsolation | Contextes differents -> cles differentes | TLC + Alloy |
| INV-07 | ZeroizeComplete | Zeroization implique derivation prealable | TLC |
| INV-08 | EnvelopePresent | User inscrit a un record envelope | TLC |
| INV-09 | DocKeyIsolation | DocIds differents -> cles doc differentes (salt=docId) | TLC + Alloy |
| INV-10 | MetadataBinding | Chaque envelope a un metadata_tag non-nul | TLC + Alloy |
| INV-11 | AuditAppendOnly | Audit log ne perd jamais d'entrees (append-only) | TLC |
Note sur TLC : Le model checking utilise une configuration bornee (MAX_USERS=1, MAX_DEVICES=2, MAX_DOCS=2, MAX_ITERATIONS=12). La verification TLC est bornee : elle explore exhaustivement l'espace d'etats dans ces limites. Des garanties complementaires proviennent des assertions structurelles Alloy (scope 5, solveur SAT) et des schemas Z (invariants universels). Les theoremes TLA+ (THM-01 a THM-08) fournissent des preuves par induction non bornees.
4.3 Theoremes prouves¶
Les theoremes suivants sont demontres en logique temporelle (TLA+) :
- THM-01 :
Spec => []TypeInvariant - THM-02 :
Spec => []OneMasterPerUser - THM-03 :
Spec => []BlacklistEnforced - THM-04 :
Spec => []VersionMonotone - THM-05 :
Spec => []ZeroizeComplete - THM-06 :
Spec => []DocKeyIsolation - THM-07 :
Spec => []MetadataBinding - THM-08 :
Spec => []AuditAppendOnly
4.4 Assertions structurelles (Alloy)¶
Les assertions suivantes sont prouvees par le solveur SAT (UNSAT = pas de contre-exemple) :
| Assertion | Propriete | Resultat |
|---|---|---|
| EveryUserHasMaster | Tout utilisateur a un master envelope | UNSAT (prouve) |
| WrappedSizeAlways40 | Taille enveloppee toujours 40 bytes | UNSAT (prouve) |
| HKDFContextSep | Contextes differents -> cles differentes | UNSAT (prouve) |
| HKDFSaltSep | Salts differents (docIds) -> cles differentes | UNSAT (prouve) |
| Argon2AlwaysId | Type Argon2 toujours 2 | UNSAT (prouve) |
| Argon2PassesStrict | Passes Argon2 toujours >= 3 | UNSAT (prouve) |
| VersionsPositive | Versions toujours >= 1 | UNSAT (prouve) |
| MetadataBindingValid | Metadata tag lie a chaque envelope | UNSAT (prouve) |
| RecoveryBIP39Present | Recovery envelope -> BIP-39 associe | UNSAT (prouve) |
5. Considerations de securite¶
5.1 Modele de menace¶
| Menace | Mitigation | Verification |
|---|---|---|
| Compromission serveur | K_master jamais en clair sur le serveur | Architecture zero-knowledge |
| Vol de base de donnees | Enveloppes chiffrees, inutilisables sans password | AES-KW (RFC 3394) |
| Brute-force password | Argon2id avec memory >= 64 MiB, passes >= 3 | ENV-01, ENV-02, ENV-03 |
| Compromission device | Revocation + blacklist | INV-04 |
| Rollback de version | Version monotone + audit trail append-only | INV-05, INV-11, ENV-23 |
| Tampering metadonnees | Metadata binding HMAC | INV-10, ENV-17, ENV-18 |
| Cross-context key reuse | HKDF context separation | INV-06, Alloy ContextSeparation |
| Cross-document key reuse | HKDF salt=docId separation | INV-09, Alloy SaltSeparation |
| Fuite memoire cle | Zeroization adaptee au runtime | INV-07, ENV-15, section 3.9 |
| Perte mot de passe | Recovery BIP-39 (24 mots) | ENV-20, ENV-22 |
5.2 Tailles de cles¶
Toutes les cles cryptographiques utilisent 256 bits (32 bytes), conforme a NIST SP 800-131A pour la securite post-2030.
5.3 K_search : leakage deterministe¶
K_search est derivee avec un salt fixe par utilisateur (user_salt, pas par document) pour permettre la recherche chiffree (Searchable Symmetric Encryption). K_search est deterministe : pour un meme (K_master, user_salt), elle produit toujours la meme cle. La portee de ce determinisme couvre les tokens/keywords indexes pour la recherche chiffree. Cette propriete est inherente au design :
- Avantage : Permet de construire un index chiffre consultable sans dechiffrer les documents.
- Risque : Un adversaire observant les requetes peut deduire des patterns d'acces (frequency analysis). Ce risque est documente et accepte.
- Mitigation : K_search est utilisee uniquement pour l'indexation. Le contenu des documents est chiffre avec K_doc_i (salt=docId, non deterministe au niveau global).
5.4 Limitations connues¶
- Le protocole ne protege pas contre un adversaire qui observe la memoire du client en temps reel (cold boot attack). La zeroization reduit la fenetre d'exposition mais ne l'elimine pas, en particulier en JavaScript/V8 (voir section 3.9).
- La recovery envelope (BIP-39) suppose que le mnemonic est stocke hors-ligne par l'utilisateur. Une perte du mnemonic ET du mot de passe entraine une perte irrecuperable de K_master.
- Le model checking TLA+ est borne (voir note section 4.2). Des garanties complementaires proviennent des assertions structurelles Alloy et des schemas Z.
6. Ancrage au code reel¶
Les specifications formelles sont ancrees aux artefacts reels du code ProbatioVault via extract-facts.py. Cet ancrage garantit que les modeles ne divergent pas de l'implementation.
| Systeme | Mecanisme d'ancrage | Verification |
|---|---|---|
| TLA+ | ASSUME verifiant les etats DB et l'infrastructure | Echec TLC si divergence |
| Alloy | one sig Real_* + fact some Real_* | Echec SAT si artefact manquant |
| Z | Schemas valides contre entities TypeORM | Lint FAIL si non matche |
| Prolog | Facts extraits du code vs regles de conformite | 24 checks bloquants |
7. Annexes¶
7.1 Specifications formelles associees¶
| Fichier | Systeme | Contenu |
|---|---|---|
PV_Envelope.tla | TLA+ | Modele temporel (9 actions, 11 invariants, 8 theoremes) |
PV_Envelope.cfg | TLA+ | Configuration TLC (MAX_USERS=1, MAX_DEVICES=2, MAX_DOCS=2) |
PV_Envelope.als | Alloy | Modele structurel (12 facts, 9 assertions, 3 runs) |
PV_Envelope.zed | Z | Specification ensembliste (14 invariants, 9 theoremes) |
pv_envelope_compliance.pl | Prolog | 24 regles de conformite code |
7.2 Vecteurs de test¶
| Test | Entree | Sortie attendue |
|---|---|---|
| Wrap roundtrip | K_master = 32 bytes aleatoires | unwrap(wrap(K_master)) == K_master |
| Wrapped size | K_master = 32 bytes | len(wrapped) == 40 |
| HKDF context isolation | contexte share vs doc | K_share != K_doc |
| HKDF salt isolation | docId1 vs docId2 | K_doc_1 != K_doc_2 |
| Argon2id type | params.type | == 2 |
| Argon2 passes | params.passes | >= 3 |
| Blacklist | revoke(device1) + createDeviceEnvelope(device1) | ERREUR |
| Metadata tag | envelope.metadata_tag | != null |
| BIP-39 word count | recovery.mnemonic.length | == 24 |
| Audit append | rotate(uid) | audit_log.length incremente |
| K_master CSPRNG | K_master genere | 32 bytes, entropie >= 256 bits (ENV-14) |
| HKDF SHA-256 | derive K_share avec HMAC-SHA512 | ERREUR (ENV-26, SHA-256 seul) |
| HKDF binary salt | user_salt en hex string | ERREUR (ENV-27, octets bruts requis) |
| Argon2 profil P1 | envelope.argon2Profile | == "PV-ARGON2-P1" (ENV-28) |
| Argon2 profil legacy | envelope avec profil anterieur | Unwrap OK (retrocompatibilite), wrap avec profil courant |
| BIP-39 wordlist FR | recovery avec wordlist francaise | ERREUR (ENV-29, anglais uniquement) |
| BIP-39 wordlist checksum | SHA-256 de la wordlist | == 2f5eed53...e7d6 (ENV-29) |
| Metadata tag binary | canonical_binding concatene | uid(16) + envelope_id(16) + version(4) + type(1) + algo(LP) + salt(16+) |
7.3 Matrice de tracabilite exigences <-> modeles formels¶
| Exigence | TLA+ | Alloy | Z | Prolog |
|---|---|---|---|---|
| ENV-01 (Argon2id) | - | Argon2TypeAlways2 | INV-04 | check_9106_argon2_type |
| ENV-04 (wrapped=40) | - | WrappedSizeConsistent | INV-03 | check_envelope_columns |
| ENV-07 (context sep) | INV-06 | ContextSeparation | INV-06 | check_5869_context_separation |
| ENV-07b (salt sep) | INV-09 | SaltSeparation | INV-11 | check_hkdf_doc_salt |
| ENV-09 (1 master) | INV-02 | OneMasterPerUser | INV-02 | check_envelope_service |
| ENV-10 (blacklist) | INV-04 | BlacklistEnforced | INV-07 | check_envelope_revoke |
| ENV-12 (version) | INV-05 | VersionPositive | INV-08 | check_envelope_versioning |
| ENV-16 (zeroize) | INV-07 | - | INV-09 | check_3394_zeroize |
| ENV-17 (metadata) | INV-10 | MetadataBindingValid | INV-12 | check_metadata_binding |
| ENV-20 (BIP-39) | - | RecoveryBIP39Present | BIP39Recovery | check_bip39_recovery |
| ENV-23 (audit) | INV-11 | AuditCoherence | INV-13 | check_audit_trail |
| ENV-25 (user_salt) | - | - | User.userSalt | check_user_salt |
| ENV-14 (K_master CSPRNG) | - | - | - | check_kmaster_generation |
| ENV-26 (HKDF HMAC-SHA256) | - | - | - | check_5869_hkdf_algorithm |
| ENV-27 (HKDF binary encoding) | - | - | - | check_5869_hkdf_encoding |
| ENV-28 (Argon2 profile versioning) | - | - | - | check_argon2_profile |
| ENV-29 (BIP-39 english wordlist) | - | - | - | check_bip39_wordlist |
| ENV-30 (zeroization documentation) | - | - | - | - |
7.4 Historique des revisions¶
| Version | Date | Description |
|---|---|---|
| 1.0.0 | 2026-02-25 | Version initiale, generee depuis modeles formels verifies |
| 1.1.0 | 2026-02-25 | 8 corrections issues de review croisee : HKDF salt=docId, metadata binding, audit trail, K_search doc, BIP-39, Argon2 durci, zeroization/runtime, TLC caveat |
| 1.2.0 | 2026-02-25 | Review croisee v2 : metadata binding client-side, K_recovery HKDF 32 bytes, audit immutabilite, user_salt spec |
| 1.3.0 | 2026-02-25 | Review croisee v3 : user_salt formel (ENV-25), K_search determinisme explicite, TLC caveat reformule, audit WORM/blockchain, Z spec alignee (Envelope, User, BIP39) |
| 1.4.0 | 2026-03-02 | ENV-26/27 encodages binaires HKDF (RFC 5869 HMAC-SHA256, entrees octets bruts), ENV-17 metadata_tag HMAC-SHA256 concatenation binaire exacte, ENV-28 profil Argon2id versionne PV-ARGON2-P1, ENV-29 BIP-39 wordlist anglaise figee (SHA-256 checksum), ENV-14 generation K_master CSPRNG 256 bits, ENV-30 documentation zeroization runtime obligatoire |