Spécification du format de preuve
Ce document décrit le format des preuves VerifBox avec assez de précision pour que n’importe qui puisse vérifier une preuve sans VerifBox. Version 1.1, octobre 2026 : ajoute l’ancrage de l’attestation (section 7) et le jeton d’horodatage IIC TSA (section 11) ; le contenu signé est inchangé, les preuves antérieures restent donc valables.
1. Principe
Une preuve VerifBox lie l’empreinte SHA-256 d’un fichier à une date et une heure, au moyen de deux signatures indépendantes : Ed25519 (RFC 8032) et ML-DSA-65 (NIST FIPS 204). Elle peut être complétée par deux ancrages OpenTimestamps dans la blockchain Bitcoin et par un jeton d’horodatage RFC 3161. Le fichier lui-même n’est jamais envoyé au service.
2. Fichier de preuve (.verifbox.json)
{
"contenu": {
"format": "verifbox-preuve-1",
"emetteur": "verifbox.com",
"algorithme": "SHA-256",
"empreinte": "<SHA-256 du fichier, 64 caractères hexadécimaux en minuscules>",
"horodatage": "<date et heure UTC, ISO 8601, ex. 2026-10-03T07:12:22.736Z>",
"identifiant": "<identifiant de la preuve, 32 caractères hexadécimaux>",
"cle": "<identifiant de la clé de signature, 16 caractères hexadécimaux>"
},
"signatures": { "ed25519": "<base64url>", "ml_dsa_65": "<base64url>" },
"ancrages": {
"bitcoin": { "format": "opentimestamps", "etat": "...", "ots": "<base64>" },
"attestation": { "format": "opentimestamps", "etat": "...", "ots": "<base64>" }
},
"jetons": {
"iic_tsa": { "format": "rfc3161", "emetteur": "IIC TSA", "politique": "...", "heure": "...", "serie": "...", "tsr": "<base64>" }
},
"informatif": { "fichier": "...", "taille": 0, "note": "..." }
}
Format strict. Les sept champs de contenu sont tous obligatoires et aucun autre champ n’est admis : format vaut verifbox-preuve-1 ; emetteur vaut verifbox.com ; algorithme vaut SHA-256 ; empreinte compte 64 caractères hexadécimaux en minuscules ; identifiant en compte 32 et cle 16, en minuscules ; horodatage est une date et heure UTC au format ISO 8601 terminée par Z, avec au plus six décimales. Les signatures sont des chaînes base64url sans remplissage, qui se décodent en exactement 64 octets (Ed25519) et 3 309 octets (ML-DSA-65). Un vérificateur doit rejeter toute preuve non conforme, ainsi que tout fichier de preuve de plus de 1 Mo.
Seul contenu est signé. ancrages, jetons et informatif ne le sont pas : les ancrages et le jeton portent leur propre preuve (sections 7 et 11), et les champs informatifs ne servent qu’à la commodité. jetons est facultatif.
3. Message signé
Toutes les valeurs de contenu sont des chaînes ASCII. Sa forme canonique est la sérialisation JSON avec les clés triées par ordre lexicographique, sans aucun espace, et un échappement en ASCII seul (Python : json.dumps(contenu, sort_keys=True, separators=(",", ":"), ensure_ascii=True)).
Le message signé est l’encodage UTF-8 du préfixe verifbox-preuve-v1 suivi d’un saut de ligne (0x0A), puis de la forme canonique. Les deux signatures portent sur ce même message, sans hachage préalable :
- Ed25519, mode pur (RFC 8032), signature de 64 octets ;
- ML-DSA-65, mode pur, contexte vide (FIPS 204), signature de 3 309 octets.
Les signatures sont encodées en base64url, sans remplissage.
4. Fichier des clés publiques
Les clés publiques sont publiées à l’adresse /.well-known/verifbox-cles.json, au format verifbox-cles-2 :
{
"format": "verifbox-cles-2",
"cles": [{
"cle": "258e57366bcdb6ce",
"statut": "active", <- active | retiree | revoquee
"valide_depuis": "2026-10-03T06:20:00Z",
"valide_jusqu": null, <- date de retrait, ou null
"revoquee_le": "...", <- seulement si la clé est révoquée
"ed25519_public": "<base64url, 32 octets>",
"mldsa65_public": "<base64url, 1 952 octets>",
"attestation": { ... } <- absente pour la clé racine
}]
}
L’identifiant de clé correspond aux 16 premiers caractères hexadécimaux de SHA-256(clé publique Ed25519 ‖ clé publique ML-DSA-65), calculé sur les octets bruts. Une clé retirée reste publiée définitivement, pour que les preuves qu’elle a signées restent vérifiables.
Clés de test. Les clés utilisées pour des tests, des évaluations ou des preuves de concept sont générées séparément des clés de production, portent leurs propres identifiants et ne figurent jamais dans le fichier de clés de production. Aucune clé privée, de production ou de test, n’apparaît dans les dépôts ou les exemples publiés.
5. Cycle de vie des clés
Clé racine et confiance. La première clé ne porte pas d’attestation. Un vérificateur doit définir ses clés racines à partir d’une source de confiance, et les identifier par le SHA-256 complet de leurs deux clés publiques, comparé aux publications indépendantes (section 6). Un fichier de clés obtenu par une autre voie ne peut qu’ajouter des clés attestées par une clé déjà reconnue, et rendre des clés connues plus restrictives (retirées, révoquées) : il ne peut jamais ajouter une clé racine ni lever une révocation. La clé racine en service est 258e57366bcdb6ce, dont l’empreinte complète est 258e57366bcdb6ce16cc22fe972c638346de2a5415327154a030e5a6b9293946.
Rotation. Lorsqu’une clé est remplacée, l’ancienne signe la nouvelle. L’attestation contient par (identifiant de l’ancienne clé), date et les deux signatures, calculées sur le préfixe verifbox-transition-v1 suivi d’un saut de ligne, puis sur la forme canonique de {"ancienne", "nouvelle", "date", "ed25519_public", "mldsa65_public"}, les deux dernières valeurs étant celles de la nouvelle clé. L’ancienne clé passe alors au statut retiree, avec valide_jusqu égal à la date de transition.
Règles temporelles. Une attestation doit être datée pendant la période de validité de la clé qui atteste (entre son valide_depuis et, s’il est renseigné, son valide_jusqu). La validité d’une clé attestée commence à la plus tardive de deux dates : son valide_depuis et la date de son attestation. Cette dernière étant couverte par les signatures de l’attestation, elle ne peut pas être avancée en modifiant le fichier de clés. Une preuve datée d’avant le début de validité de sa clé est invalide.
Dater une rotation n’est pas l’autoriser. Un ancrage Bitcoin peut montrer quand une transition existait ; il ne montre pas qu’elle était autorisée. L’autorisation vient de l’attestation signée par la clé précédente (Ed25519 et ML-DSA-65) et de la publication indépendante du fichier de clés (DNS, GitHub). Un vérificateur s’appuie sur les deux, jamais sur un ancrage seul. Le fichier de clés indique, pour chaque clé, la clé précédente, la date de transition, le statut, la période de validité et, le cas échéant, la date de révocation.
Fichiers de clés restrictifs. Comme un fichier de clés obtenu par une autre voie peut rendre des clés connues plus restrictives, il peut faire refuser une preuve valide ; il ne peut jamais faire accepter une preuve invalide. Un vérificateur doit indiquer quelles clés ont été acceptées et rejetées.
Révocation. Si une clé privée est compromise, la clé est marquée revoquee, avec la date revoquee_le. Comme le détenteur de la clé pourrait produire des attestations antidatées, une preuve signée par une clé révoquée n’est fiable que si l’ancrage Bitcoin de son attestation (section 7) figure dans un bloc antérieur à la révocation. L’ancrage du fichier ne suffit pas : il montre que le fichier existait, pas que cette attestation a été émise avant le vol de la clé. Pour une preuve sans ancrage de son attestation (émise avant la version 1.1), la date signée ne peut plus être retenue après une révocation ; tout au plus, l’ancrage du fichier montre que le fichier existait avant son bloc. Une clé révoquée ne peut plus attester une autre clé.
Journal des révocations. Le fichier de clés est le registre public de l’état des clés : chaque retrait et chaque révocation y figure avec sa date, et se retrouve dans la publication DNS et sur GitHub. L’historique des versions du dépôt GitHub conserve chaque état publié du fichier de clés, avec sa date, ce qui permet de vérifier l’état d’une clé à n’importe quel moment passé.
6. Publication indépendante (racine de confiance)
L’empreinte SHA-256 du fichier des clés publiques est publiée hors de verifbox.com, par des canaux qui ne dépendent pas du service :
- DNS d’internetidentitycard.com, signé par DNSSEC : enregistrement TXT
_verifbox.internetidentitycard.com, de la formeverifbox-cle=<identifiant> sha256=<empreinte du fichier de clés> depuis=<date>. Vérification :dig +dnssec TXT _verifbox.internetidentitycard.com. - Dépôt GitHub : https://github.com/httpscard/verifbox-cles, qui conserve une copie du fichier de clés et son empreinte, avec un historique daté.
Comparez le SHA-256 de /.well-known/verifbox-cles.json à ces publications. Toute rotation de clé s’accompagne de leur mise à jour.
7. Ancrage Bitcoin
ancrages.bitcoin.ots est un fichier OpenTimestamps standard (horodatage détaché, opération SHA-256), encodé en base64. L’empreinte de fichier qu’il contient doit être égale à contenu.empreinte. Il se vérifie avec le client officiel : ots verify fichier.ots. L’ancrage établit que le fichier existait avant la date du bloc Bitcoin, indépendamment de VerifBox et de ses clés.
Ancrage de l’attestation. Depuis la version 1.1, ancrages.attestation.ots est un second fichier OpenTimestamps, construit de la même manière, dont l’empreinte de fichier est celle de l’attestation signée :
SHA-256( "verifbox-attestation-v1\n" + canonical(contenu) + "\n" + signatures.ed25519 + "\n" + signatures.ml_dsa_65 )
où les chaînes sont encodées en UTF-8, la forme canonique est celle de la section 3 et les signatures sont les chaînes base64url de la preuve. Cet ancrage prouve que cette attestation précise, avec sa date signée, existait avant la date de son bloc Bitcoin. C’est lui qui permet à une preuve de rester fiable après la révocation de sa clé. Il se vérifie avec le client officiel : ots verify -d <empreinte de l’attestation> attestation.ots.
Ce qu’un ancrage établit, et ce qu’il n’établit pas. Trois notions doivent rester distinctes. L’heure déclarée (horodatage) est l’heure donnée par VerifBox et couverte par sa signature. Un ancrage Bitcoin établit une borne : l’empreinte ancrée était engagée au plus tard au moment de son bloc. L’horodatage des blocs n’est pas précis à la seconde ; il peut s’écarter du temps réel d’environ deux heures. Le statut de révocation d’une clé est une troisième question, distincte : il dépend de la fraîcheur du fichier de clés utilisé par le vérificateur. Un ancrage ne prouve jamais l’instant exact de création d’un fichier.
8. Algorithme de vérification
- Calculer le SHA-256 du fichier d’origine et le comparer à
contenu.empreinte. - Obtenir le fichier des clés publiques, et comparer son SHA-256 à sa publication indépendante (section 6).
- Trouver l’entrée dont
cleest égal àcontenu.cle, et recalculer l’identifiant à partir de ses deux clés publiques. - Vérifier la chaîne d’attestations jusqu’à une clé racine.
- Vérifier que
horodatageest compris entrevalide_depuisetvalide_jusqu. - Reconstituer le message signé et vérifier les deux signatures. Les deux doivent être valides.
- Si les ancrages sont présents, vérifier que l’empreinte de l’ancrage du fichier est égale à
empreinteet que celle de l’ancrage de l’attestation est égale à l’empreinte de l’attestation (section 7), puis les vérifier contre Bitcoin. - Si la clé est révoquée, n’accepter la preuve que si l’ancrage de son attestation figure dans un bloc antérieur à la révocation.
- Si la preuve contient un jeton IIC TSA, le vérifier (section 11). Un jeton invalide rend la preuve invalide ; une preuve sans jeton reste valable.
9. Vérificateurs indépendants
Dans un navigateur, hors ligne : verifbox-verify-offline.html, publié sur GitHub, est une page HTML unique qui contient les bibliothèques cryptographiques et le fichier des clés publiques. Son code source peut être lu sur GitHub avant tout téléchargement. Une fois enregistrée sur votre ordinateur, elle s’ouvre dans n’importe quel navigateur et fonctionne sans aucune connexion internet ; sa politique de sécurité lui interdit toute requête réseau. Elle vérifie l’empreinte du fichier, les deux signatures et le cycle de vie de la clé, et extrait le fichier .ots. C’est une solution de secours, pour le cas où verifbox.com ne serait pas accessible : la page Vérifier de ce site reste le moyen habituel de contrôler une preuve.
En Python :
Un vérificateur qui applique cet algorithme, en un seul fichier Python sans aucune dépendance à VerifBox, est disponible : verifbox_verify.py (licence MIT), sur GitHub ou sur verifbox.com.
pip install cryptography dilithium-py
python3 verifbox_verify.py preuve.verifbox.json fichier-original --ots ancrage.ots
ots verify ancrage.ots
Il télécharge le fichier de clés depuis verifbox.com (ou utilise une copie locale avec --keys) et compare automatiquement son empreinte à la publication DNS, validée par DNSSEC. Avec --offline, il fonctionne sans aucun accès réseau.
Le numéro de bloc qu’il affiche est lu dans le fichier .ots lui-même et n’est pas vérifié contre Bitcoin ; les champs bloc et etat de ancrages, qui ne sont pas signés, ne sont jamais présentés comme faisant foi.
Ce que couvre la vérification hors ligne. Sans aucun accès réseau, un vérificateur peut contrôler l’empreinte du fichier, les deux signatures, les identifiants et la chaîne d’attestations des clés, les dates de validité, et que les deux ancrages portent bien sur ce fichier et cette attestation (contrôle structurel). Deux choses exigent une information externe et à jour : confirmer les ancrages contre la blockchain Bitcoin, et connaître l’état actuel d’une clé. Un résultat hors ligne sur la révocation vaut à la date du fichier de clés utilisé, et doit être comparé aux publications indépendantes dès qu’un réseau est disponible.
10. Vecteur de test
Les valeurs suivantes proviennent d’une preuve réelle, émise le 3 octobre 2026, et permettent de contrôler n’importe quelle implémentation. Son contenu est :
{
"format": "verifbox-preuve-1",
"emetteur": "verifbox.com",
"algorithme": "SHA-256",
"empreinte": "b1382589c3d05a7096e4a328a77fa743c0dd9714e5e45a8aa8e81be0ff29f10c",
"horodatage": "2026-10-03T07:12:22.736Z",
"identifiant": "3145d9d82f124d8fb3c8ae863b644c79",
"cle": "258e57366bcdb6ce"
}
Forme canonique (une ligne, sans espace) :
{"algorithme":"SHA-256","cle":"258e57366bcdb6ce","emetteur":"verifbox.com","empreinte":"b1382589c3d05a7096e4a328a77fa743c0dd9714e5e45a8aa8e81be0ff29f10c","format":"verifbox-preuve-1","horodatage":"2026-10-03T07:12:22.736Z","identifiant":"3145d9d82f124d8fb3c8ae863b644c79"}
SHA-256 du message signé (préfixe verifbox-preuve-v1 et saut de ligne, puis forme canonique) : f534d90d90f99cc7ecc129ae75eaa88d8bc892681162ea07670aa80617f90f68
Signature Ed25519, qui se vérifie avec la clé publique 258e57366bcdb6ce publiée dans verifbox-cles.json :
MwONZqUvQacifN3ulnzGp9jJO_m_913SgNMb9gDjmnJAieXJTO4hAFoHG9DluYI1lOdiR5kYWb0VcNbUcldbCA
11. Jeton d’horodatage RFC 3161 (IIC TSA)
À partir de l’ouverture du service IIC TSA, une preuve peut contenir jetons.iic_tsa.tsr : une réponse d’horodatage RFC 3161 (avec l’identification du certificat de la RFC 5816), encodée en DER puis en base64. Le jeton porte sur contenu.empreinte, c’est-à-dire sur l’empreinte SHA-256 du fichier, comme l’ancrage Bitcoin du fichier ; il se vérifie donc avec le seul fichier d’origine. Les champs politique, heure et serie en sont des copies informatives : seul le jeton fait foi.
Vérification. Le statut est accordé ; l’empreinte du jeton (SHA-256) est égale à contenu.empreinte ; la politique est 1.3.6.1.4.1.67100.1.1.1.1 ; les attributs signés comprennent le type de contenu id-ct-TSTInfo, l’empreinte SHA-256 du TSTInfo et l’identification SHA-256 du certificat de signature ; la signature ECDSA P-256 avec SHA-256 est valide ; le certificat est émis par la racine IIC TSA publiée dans /.well-known/iic-tsa.json, avec le seul usage horodatage, marqué critique ; l’heure du jeton est comprise dans sa période de validité ; et le certificat n’a pas été révoqué avant cette heure, selon la liste de révocation signée par la racine (iic-tsa-racine.crl). Avec OpenSSL :
openssl ts -verify -in jeton.tsr -data fichier-original -CAfile iic-tsa-racine.pem
Le fichier .tsr s’obtient avec le bouton « Jeton IIC TSA (.tsr) » de la page Vérifier, ou avec verifbox_verify.py --tsr jeton.tsr.
Heure du jeton et heure déclarée. Le jeton est demandé en même temps que la signature : les deux heures diffèrent normalement d’une ou deux secondes. Un vérificateur signale tout écart supérieur à dix secondes. Le jeton déclare une précision de ± 1 seconde ; avant chaque jeton, l’horloge d’IIC TSA est comparée à quatre sources indépendantes jointes par liaison chiffrée : l’horloge web de la PTB, institut national de métrologie allemand (source traçable à l’UTC), Akamai, Google et Cloudflare ; sans accord d’au moins trois d’entre elles, dont la PTB, aucun jeton n’est délivré.
Transparence. IIC TSA est exploité par HTTPS CARD — Internet Identity Card Limited, la société qui édite VerifBox : ce n’est pas un tiers indépendant. C’est un service d’horodatage non qualifié au sens du règlement (UE) n° 910/2014 (eIDAS). Le jeton apporte une heure à la seconde, sous une politique publiée et vérifiable avec des outils standard ; les deux ancrages Bitcoin restent, eux, indépendants de nous.
Contrôle du journal d’IIC TSA. Chaque jeton est inscrit dans un journal qui ne peut être ni modifié ni effacé pendant douze ans. Chaque nuit, l’empreinte SHA-256 du journal de la veille est horodatée par le serveur RFC 3161 public de DigiCert (FreeTSA en secours), utilisé sans contrat, puis ancrée dans Bitcoin par OpenTimestamps : un jeton ne peut pas être antidaté après coup sans que cela se voie.
Absence de jeton. Le jeton est facultatif : si IIC TSA ne répond pas, la preuve est délivrée sans lui et reste valable. Les preuves émises avant l’ouverture du service n’en contiennent pas.