PD-38 — Calcul de l'empreinte probatoire SHA3-256 sur documents chiffrés¶
📚 Navigation User Story
| Document | | | ---------- | -- | | 📋 **Spécification** | *(ce document)* | | 🛠️ [Plan d'implémentation](PD-38-plan.md) | | | ✅ [Critères d'acceptation](PD-38-acceptability.md) | | | 📝 [Retour d'expérience](PD-38-rex.md) | | [← Retour à crypto-proof](../PD-189-epic.md) · [↑ Index User Story](index.md)Références¶
- EPIC : CRYPTO-PROOF (PD-189)
- JIRA : PD-38
- Repo(s) concernés : backend
Objectif¶
Implémenter le calcul systématique d'une empreinte cryptographique probatoire basée sur l'algorithme SHA3-256, appliquée exclusivement aux documents chiffrés, afin de garantir leur intégrité, leur non-altération et leur opposabilité juridique dans le temps.
Cette empreinte constitue la base de toute la chaîne probatoire (signature HSM, horodatage TSA, ancrage blockchain, preuves composites).
Description fonctionnelle¶
Lors du dépôt d'un document dans ProbatioVault, le système doit calculer une empreinte cryptographique à partir du fichier chiffré transmis par le client.
Cette empreinte permet :
- de prouver l'intégrité du document sans jamais en révéler le contenu ;
- de vérifier qu'aucune modification n'a été apportée au fichier ;
- de servir d'entrée aux mécanismes probatoires avancés (Merkle tree, signature, horodatage, blockchain).
Le calcul de l'empreinte ne doit à aucun moment nécessiter le déchiffrement du document, garantissant ainsi le respect strict du modèle zero-knowledge.
Périmètre¶
Inclus¶
- Calcul d'une empreinte SHA3-256 à partir du fichier chiffré.
- Caractère déterministe du calcul (même fichier → même empreinte).
- Association de l'empreinte au document dès l'upload.
- Stockage de l'empreinte dans la base de données.
- Restitution de l'empreinte via l'API pour vérification ultérieure.
- Support de fichiers de taille variable, y compris volumineux.
- Tests fonctionnels et techniques validant la conformité cryptographique.
Exclu¶
- Calcul de hash sur des documents en clair.
- Mécanismes de signature cryptographique.
- Horodatage TSA.
- Construction d'arbres de Merkle.
- Ancrage blockchain.
- Vérification client-side de l'empreinte.
Contraintes¶
- Sécurité
- Le hash est calculé exclusivement sur le fichier chiffré.
- Aucune donnée en clair ne doit être accessible au service.
- Aucune fuite de l'empreinte ne doit apparaître dans les logs.
-
Toute tentative de hash sur un fichier vide ou invalide doit être rejetée.
-
Conformité cryptographique
- Utilisation exclusive de l'algorithme SHA3-256 (NIST FIPS 202).
- Taille de sortie fixe de 256 bits.
- Résistance aux collisions conforme à l'état de l'art.
-
Compatibilité avec les exigences NF Z42-013 et ISO 14641.
-
Performance
- Le calcul doit être compatible avec des volumes importants.
- Le traitement ne doit pas provoquer de surcharge mémoire.
-
Le calcul doit rester compatible avec un usage en production.
-
Qualité
- Couverture de tests élevée sur le service de calcul.
- Absence de régression sur le flux d'upload documentaire.
- Conformité aux règles de qualité et de sécurité du projet.
Hypothèses¶
- Les documents sont toujours chiffrés côté client avant transmission.
- Le stockage du document chiffré est opérationnel.
- Le schéma de base de données permet l'ajout d'une empreinte probatoire.
- Les mécanismes probatoires ultérieurs consomment cette empreinte comme entrée de confiance.
- Les exigences légales imposent un hash indépendant du contenu en clair.
Spécifications techniques¶
Implémentation¶
| Élément | Valeur |
|---|---|
| Bibliothèque | js-sha3 (ou noble-hashes) |
| Algorithme | SHA3-256 (Keccak) |
| Output | 64 caractères hexadécimaux (256 bits) |
| Colonne DB | file_hash VARCHAR(64) UNIQUE |
| Streaming | Supporté pour fichiers volumineux |
Stockage base de données¶
-- Colonne dans vault_secure.documents
file_hash VARCHAR(64) NOT NULL UNIQUE
-- Contrainte : CHECK (file_hash ~ '^[a-f0-9]{64}$')
Exemple d'utilisation¶
import { sha3_256 } from 'js-sha3';
// Hash d'un buffer
const hash = sha3_256(encryptedFileBuffer);
// Résultat : "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
// Version streaming pour gros fichiers
const hasher = sha3_256.create();
for await (const chunk of fileStream) {
hasher.update(chunk);
}
const hashStreaming = hasher.hex();
Diagrammes¶
Séquence — Calcul et persistance de l'empreinte probatoire¶
Ce diagramme couvre le flux nominal d'upload avec calcul SHA3-256 sur le ciphertext, stockage en base et restitution.
Les invariants référencés : - Hash sur ciphertext uniquement : le backend ne déchiffre jamais le document (zero-knowledge). - Fichier vide = rejet : toute donnée vide ou invalide est rejetée avant calcul. - Unicité hash par utilisateur : contrainte UNIQUE en base. - Hash jamais en clair dans les logs : aucune empreinte n'apparait dans les traces applicatives.
sequenceDiagram
participant Client
participant API as DocumentController
participant DSS as DocumentSecureService
participant S3 as OVH S3 (WORM)
participant HS as HashService
participant DB as PostgreSQL
Client->>+API: POST /documents (ciphertext)
API->>+DSS: create(dto, file)
Note over DSS: Validation : fichier non vide<br/>(rejet BadRequest si vide/invalide)
DSS->>+S3: putObject(ciphertext)
S3-->>-DSS: objectKey
DSS->>+S3: getObject(objectKey)
S3-->>-DSS: ciphertext stream
DSS->>+HS: hashDocumentStream(stream)
Note over HS: SHA3-256 (FIPS 202)<br/>Streaming par chunks<br/>Sortie : 64 chars hex
alt Stream vide
HS-->>DSS: BadRequestException
DSS-->>API: 400 Bad Request
API-->>Client: 400 Bad Request
else Stream valide
HS-->>-DSS: fileHash (64 hex)
end
DSS->>+DB: INSERT document (fileHash)
Note over DB: UNIQUE constraint sur file_hash<br/>CHECK (file_hash ~ '^[a-f0-9]{64}$')
alt Hash dupliqué
DB-->>DSS: ConflictException
DSS-->>API: 409 Conflict
API-->>Client: 409 Conflict
else Insertion OK
DB-->>-DSS: document entity
end
DSS-->>-API: document (avec fileHash)
API-->>-Client: 201 Created (document) Séquence — Vérification d'intégrité¶
Ce diagramme couvre le flux de vérification a posteriori de l'empreinte probatoire d'un document stocké.
sequenceDiagram
participant Client
participant API as DocumentController
participant DSS as DocumentSecureService
participant S3 as OVH S3 (WORM)
participant HS as HashService
participant DB as PostgreSQL
Client->>+API: GET /documents/:id/verify
API->>+DSS: verifyIntegrity(documentId)
DSS->>+DB: findOne(documentId)
DB-->>-DSS: document (fileHash stocké)
DSS->>+S3: getObject(objectKey)
S3-->>-DSS: ciphertext stream
DSS->>+HS: hashDocumentStream(stream)
HS-->>-DSS: computedHash
DSS->>DSS: verify(computedHash, storedHash)
Note over DSS: Comparaison constant-time<br/>(timingSafeEqual)
alt Hash identique
DSS-->>API: { integrity: true }
API-->>-Client: 200 OK — Intégrité confirmée
else Hash différent
DSS-->>API: { integrity: false }
API-->>Client: 200 OK — Intégrité compromise
end États — Cycle de vie de l'empreinte probatoire¶
L'empreinte traverse trois états principaux liés au document. Une fois calculée et persistée, elle devient l'entrée de confiance pour les mécanismes probatoires avancés (signature HSM, TSA, Merkle, blockchain).
stateDiagram-v2
[*] --> UPLOADED : Client envoie ciphertext
UPLOADED --> HASHING : Backend récupère le fichier S3
HASHING --> HASHED : SHA3-256 calculé + persisté en DB
HASHING --> REJECTED : Fichier vide / stream invalide
HASHED --> VERIFIED : Vérification intégrité OK
HASHED --> COMPROMISED : Hash recalculé ≠ hash stocké
VERIFIED --> HASHED : (état stable)
HASHED --> SIGNED : Entrée signature HSM (PD-37)
HASHED --> TIMESTAMPED : Entrée horodatage TSA (PD-39)
HASHED --> ANCHORED : Entrée Merkle tree (PD-54)
REJECTED --> [*]
note right of HASHED
Invariants :
- Hash sur ciphertext uniquement
- Unicité par utilisateur (UNIQUE DB)
- 64 chars hex (FIPS 202)
- Jamais exposé dans les logs
end note Liens documentaires¶
- Architecture :
- Architecture TechLead — Garanties probatoires
- EPIC :
- CRYPTO-PROOF (PD-189)
- Sécurité & conformité :
- Spécifications Techniques ProbatioVault v2.1
- NF Z42-013
- ISO 14641
- NIST FIPS 202 (SHA-3)