Chaînes de hachage et détection de falsification : comment un seul octet modifié invalide toute une archive
Lorsque l’on dit d’une archive de documents qu’elle est “à falsification détectable”, l’affirmation est précise : toute modification de tout enregistrement produit une incohérence que l’on peut repérer. Elle n’est pas “infalsifiable” : c’est une affirmation différente, et plus forte. “À falsification détectable” signifie que si l’archive a été modifiée, vous pouvez trouver la modification.
Les chaînes de hachage sont la construction standard pour obtenir cette propriété. Elles ne sont pas nouvelles (le concept précède la blockchain de plusieurs décennies), mais elles sont largement mal comprises, ce qui conduit à la fois à un excès de confiance et à une sous-utilisation.
Cet article explique comment fonctionnent les chaînes de hachage, ce qu’elles garantissent, ce qu’elles ne garantissent pas, et pourquoi les choix d’implémentation précis comptent.
Ce qu’est un hachage cryptographique
Une fonction de hachage cryptographique prend une entrée de longueur arbitraire et produit une sortie de longueur fixe, appelée hachage ou condensé. SHA-384 produit une sortie de 384 bits (48 octets), généralement représentée par 96 caractères hexadécimaux.
Trois propriétés rendent les fonctions de hachage utiles pour la détection de falsification :
Déterminisme. La même entrée produit toujours la même sortie. Si vous hachez deux fois le même document, vous obtenez le même hachage.
Effet avalanche. Une petite modification de l’entrée produit une sortie complètement différente. Modifier un octet dans un document de 10 000 octets produit un hachage qui ne ressemble en rien à l’original. Il est impossible de prédire à quoi ressemblera le nouveau hachage.
Sens unique. À partir d’un hachage, il est computationnellement infaisable de reconstruire l’entrée. Vous ne pouvez pas remonter du hachage jusqu’au document.
C’est la troisième propriété qui rend les chaînes de hachage contraignantes : une fois que vous publiez ou enregistrez un hachage, vous vous êtes engagé sur le contenu qui l’a produit, sans révéler ce contenu lui-même.
La construction de base
Une chaîne de hachage relie une séquence d’événements de sorte que chaque événement dépend de tous les événements précédents.
Dans l’implémentation de SealDoc, un événement de preuve contient :
- Le type d’événement (par ex.
vault.ingested,anchor.rfc3161) - Un numéro de séquence
- Un horodatage
- Les détails propres à l’événement (en JSON canonique)
- Le hachage de l’événement précédent
- Le hachage de cet événement, calculé sur tous les champs ci-dessus
Le hachage de chaque événement inclut le hachage de l’événement précédent. Cela signifie que pour reproduire le hachage de l’événement N, il vous faut le contenu exact de l’événement N et le hachage exact de l’événement N-1. Le hachage de l’événement N-1 dépendait de l’événement N-2, et ainsi de suite jusqu’au premier événement.
Le premier événement utilise une valeur genesis fixe comme “hachage précédent” : une constante bien connue que chacun peut vérifier.
Cela crée une chaîne où :
Hash(Event 1) = H("vault.ingested" | seq:1 | ts:... | details:... | genesis)
Hash(Event 2) = H("anchor.rfc3161" | seq:2 | ts:... | details:... | Hash(Event 1))
Hash(Event 3) = H("vault.storage-lock.applied" | seq:3 | ts:... | details:... | Hash(Event 2))
Ce qui se passe quand on la falsifie
Supposons qu’un adversaire veuille modifier les détails de l’événement 1. Il modifie un champ de l’événement, puis recalcule le hachage de l’événement 1. Le nouveau hachage diffère de l’original.
Mais le hachage de l’événement 2 a été calculé à partir du hachage original de l’événement 1. L’adversaire doit maintenant recalculer le hachage de l’événement 2 à partir du nouveau hachage de l’événement 1. Cela produit un hachage différent pour l’événement 2.
Dès lors, l’événement 3 porte un hachage précédent erroné. Et ainsi de suite pour chaque événement suivant.
Pour rendre la modification indétectable, l’adversaire doit recalculer les hachages de chaque événement à partir du point falsifié. Dans un système local et autonome, c’est possible. La chaîne seule ne l’empêche pas.
C’est pourquoi l’ancrage est important.
L’ancrage : rendre la chaîne vérifiable de l’extérieur
Une chaîne de hachage qui n’existe que dans votre propre base de données prouve l’intégrité au sein de votre propre système. Un adversaire qui contrôle votre base de données peut réécrire toute la chaîne. La chaîne doit être ancrée à quelque chose qui échappe à votre contrôle.
Le mécanisme standard est un horodatage RFC 3161. Le flux fonctionne ainsi :
- Au moment de la création du document, calculez le hachage de l’événement de preuve.
- Soumettez ce hachage à une Autorité d’Horodatage (TSA) indépendante.
- La TSA signe une réponse contenant votre hachage, l’horodatage de la TSA et l’identité de la TSA. Cette réponse signée est le jeton d’horodatage.
- Stockez le jeton d’horodatage à côté de la chaîne de hachage.
Le jeton d’horodatage est signé avec la clé privée de la TSA. La chaîne de certificats de la TSA est vérifiable publiquement. Quiconque dispose du document, du hachage original et du jeton d’horodatage peut vérifier de manière indépendante que le document existait dans cet état à ce moment-là, sans avoir à vous faire confiance le moins du monde.
Le problème de l’adversaire devient alors plus difficile. Pour modifier l’événement 1 sans que cela se voie, il doit :
- Modifier l’événement et recalculer tous les hachages en aval.
- Obtenir d’une TSA de confiance un nouvel horodatage RFC 3161 pour le nouveau hachage.
La seconde étape est impossible rétroactivement. L’horodatage de la TSA intègre une heure. Un horodatage affirmant que le document modifié existait à l’heure d’origine devrait avoir été émis par la TSA à cette heure d’origine, ce que l’adversaire ne peut pas organiser après coup.
Voilà ce que signifie concrètement “à falsification détectable” : non pas que la modification est empêchée au niveau physique, mais que toute modification qu’un adversaire voudrait faire passer inaperçue exige soit de compromettre la signature de la TSA indépendante, soit de réécrire l’histoire, deux choses computationnellement infaisables.
Pourquoi deux condensés, et lequel où
SHA-256 est l’algorithme de hachage le plus couramment utilisé pour cette catégorie d’applications. SealDoc l’utilise pour la chaîne de traitement et le manifeste du pack, et SHA-384 pour le registre de preuves. Les deux tournent pour chaque document ; ils répondent à des questions différentes.
La chaîne de traitement ne peut pas choisir librement. Son condensé est aussi la clé de stockage, et c’est l’empreinte de message que signe l’Autorité d’Horodatage : la ligne de preuve va donc des octets au jeton, en passant par l’empreinte. Le changer impliquerait de migrer chaque localisateur stocké et chaque jeton existant, et non de basculer un simple paramètre.
Le registre de preuves a été construit plus tard et n’est soumis à aucune contrainte de ce type, c’est pourquoi il utilise le condensé le plus long.
La différence pratique, c’est la marge. SHA-256 est actuellement considéré comme sûr, mais les recommandations cryptographiques évoluent. SHA-384 appartient à la même famille SHA-2 et se calcule de la même manière, simplement avec un état interne plus grand. Pour les archives aux longues durées de conservation (7 ans pour les factures TVA dans l’UE, jusqu’à 20 ans pour certains documents du secteur public), cette marge supplémentaire compte.
Le condensé plus long réduit aussi la probabilité (déjà négligeable) de collisions de hachage, où deux documents différents produisent le même hachage. Pour les archives de conformité, c’est une propriété significative : deux factures différentes ne devraient jamais produire le même identifiant.
Vérifier la chaîne
La vérification remonte à partir du dernier événement. Étant donné un ensemble d’événements dans l’ordre de séquence :
- Pour chaque événement, recalculez le hachage à partir des champs stockés : type d’événement, numéro de séquence, horodatage, détails et hachage précédent.
- Comparez le hachage recalculé au hachage stocké. S’ils correspondent, le contenu de l’événement n’a pas changé depuis le calcul du hachage.
- Vérifiez que le
previousHashde chaque événement correspond au hachage stocké de l’événement précédent. S’ils correspondent, la chaîne est intacte. - Pour tout événement qui porte une ancre d’horodatage RFC 3161, vérifiez le jeton d’horodatage par rapport à la chaîne de certificats de la TSA.
Le point de terminaison GET /api/vault/{recordId}/verify de SealDoc recalcule chaque hachage, vérifie chaque maillon, contrôle les signatures des événements et indique l’ancrage temporel, avec un détail par événement :
{
"chainValid": true,
"eventCount": 3,
"events": [
{
"sequenceNo": 1,
"eventType": "vault.ingested",
"hashVerified": true,
"chainLinkVerified": true,
"signaturePresent": true,
"signatureVerified": true
}
]
}
hashVerified signifie que le hachage recalculé correspond au hachage stocké. chainLinkVerified signifie que le pointeur vers le hachage précédent est cohérent. signatureVerified signifie que la signature ECDSA sur le hachage de l’événement est valide par rapport à la clé de signature connue.
Une chaîne dont chaque événement renvoie hashVerified: true et chainLinkVerified: true est une chaîne dont aucune donnée stockée n’a été modifiée. Les horodatages d’ancrage fournissent la preuve externe, vérifiable auprès de la TSA, du moment où chaque événement s’est produit.
Ce que la chaîne ne garantit pas
Rendre la falsification détectable est une propriété précise et délimitée. Il vaut la peine d’être exact sur ce qu’elle couvre et ce qu’elle ne couvre pas.
Elle n’empêche pas la suppression. Une chaîne de hachage détecte la modification des enregistrements existants, mais ne peut pas détecter qu’un enregistrement a été supprimé. Si l’événement 2 d’une chaîne de cinq événements est entièrement retiré, la chaîne se rompt, mais seulement si le vérificateur sait qu’il devrait y avoir cinq événements, et non quatre. Empêcher la suppression est une préoccupation distincte, qui relève de la couche de stockage, comme le stockage WORM.
Elle n’empêche pas le système source de mentir. Si le document a été corrompu avant d’entrer dans le pipeline, la chaîne de hachage s’engage sur cette version corrompue. La chaîne prouve l’intégrité à partir du moment de l’ingestion, et non à partir du moment de la création. C’est pourquoi la validation (contrôle de conformité PDF/A, validation du schéma Factur-X) a lieu avant que le hachage ne soit engagé.
La chaîne ne vaut que par ses ancres. Une chaîne sans ancres RFC 3161 externes est un système qui se scelle lui-même. Elle prouve la cohérence interne, mais pas l’ancrage dans le temps. Pour tout usage sérieux en matière de conformité, des horodatages ancrés auprès d’une TSA indépendante sont nécessaires.
Ce qu’il faut en retenir pour les ingénieurs
Si vous construisez un pipeline documentaire et que vous avez besoin de rendre la falsification détectable, l’implémentation est simple :
- À l’ingestion, calculez un hachage du document avec SHA-256 ou SHA-384.
- Soumettez le hachage à une TSA RFC 3161 et stockez le jeton d’horodatage renvoyé.
- Pour chaque événement suivant, liez le hachage de l’événement au hachage de l’événement précédent.
- Stockez la chaîne dans un stockage en ajout seul (aucune mise à jour ni suppression sur la table des événements).
- Exposez un point de terminaison de vérification qui recalcule et contrôle la chaîne à la demande.
La complexité conceptuelle est faible. La complexité d’implémentation vient des aspects opérationnels : gestion des clés, fiabilité de la TSA, migration de la chaîne si vous changez d’algorithme de hachage, et gestion du cas où la soumission à la TSA échoue en pleine transaction.
SealDoc prend en charge ces aspects en tant qu’infrastructure, de sorte que les pipelines qui font transiter des documents par l’API obtiennent la chaîne sans avoir à l’implémenter. Mais si vous la construisez vous-même, ce qui précède est la construction minimale viable.
Le SealDoc Evidence Vault produit un journal d’événements chaîné par hachage pour chaque document et demande un horodatage RFC 3161 à une Autorité d’Horodatage européenne indépendante. La chaîne et les horodatages sont vérifiables via GET /api/vault/{recordId}/verify sans avoir à faire confiance à l’infrastructure de SealDoc.