Chapitre 718 minIntermédiaire
HMAC et signature numérique : intégrité, authenticité, preuve
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- expliquer pourquoi un hachage seul ne prouve pas l'origine d'un message ;
- calculer et vérifier un HMAC ;
- décrire la signature et la vérification d'un document ;
- lire un jeton JWT et choisir entre HS256 et RS256 ;
- distinguer les signatures électroniques simple, avancée et qualifiée.
5 exercices corrigés1 schéma
Un HMAC et une signature numérique servent tous deux à prouver qu'un message n'a pas été modifié et qu'il vient bien de celui qui détient une clé. Le HMAC est une empreinte calculée avec une clé secrète partagée (cryptographie symétrique) ; la signature numérique est une empreinte transformée avec une clé privée et vérifiée avec la clé publique correspondante (cryptographie asymétrique), ce qui apporte en plus la non-répudiation. Ce chapitre montre pourquoi un hachage seul ne suffit pas, comment calculer et vérifier un HMAC, comment signer un fichier, comment fonctionnent les jetons JWT et ce que dit le droit de la signature électronique.
Pourquoi un hachage seul ne prouve rien
Une clinique partenaire envoie à l'API du laboratoire une commande d'analyses, accompagnée de son empreinte SHA-256 pour « garantir l'intégrité ». Un attaquant placé sur le chemin modifie la commande, recalcule l'empreinte SHA-256 de la commande modifiée et remplace l'ancienne. L'API recalcule l'empreinte, la trouve conforme et accepte la commande falsifiée. Le hachage est public : tout le monde peut le calculer, l'attaquant aussi.
Pour qu'une empreinte prouve quelque chose, il faut que son calcul exige un secret que l'attaquant n'a pas. Deux solutions :
- un secret partagé entre l'expéditeur et le destinataire : c'est le HMAC ;
- une clé privée que seul l'expéditeur possède, vérifiable par tous avec sa clé publique : c'est la signature numérique.
Le HMAC : une empreinte avec une clé secrète
Le HMAC (keyed-Hash Message Authentication Code, normalisé dans la RFC 2104 en 1997) combine une fonction de hachage et une clé secrète. Sa construction applique deux fois la fonction de hachage, avec la clé mélangée à deux constantes (notées ipad et opad) :
HMAC(K, m) = H( (K ⊕ opad) ‖ H( (K ⊕ ipad) ‖ m ) )
Tu n'as pas à retenir la formule : retiens qu'on ne fabrique pas un HMAC en écrivant sha256($cle . $message) (cette construction naïve est vulnérable à une attaque par extension de longueur), mais en appelant la fonction HMAC de son langage.
L'API d'Hélianthe partage avec chaque clinique un secret, ici cle-secrete-webhook. La clinique calcule le HMAC-SHA-256 du corps de la requête et l'envoie dans un en-tête :
printf '{"commande":42,"montant":"19.90"}' | openssl dgst -sha256 -hmac cle-secrete-webhook
# SHA2-256(stdin)= d8a48289912126682feb32469f3c6259fc8ac5e5e5863b600016c5d255cd9152
L'attaquant qui change 19.90 en 1.90 obtient un HMAC complètement différent (7dc6ab72…), et il ne peut pas calculer le bon puisqu'il n'a pas la clé. L'API recalcule le HMAC du corps reçu avec sa copie de la clé et compare :
import { createHmac, timingSafeEqual } from 'node:crypto';
function signatureValide(corpsBrut, signatureRecue, secret) {
const attendue = createHmac('sha256', secret).update(corpsBrut).digest();
const recue = Buffer.from(signatureRecue, 'hex');
// Comparaison en temps constant : une comparaison classique s'arrête au premier
// octet différent, et la durée de la réponse renseignerait l'attaquant
return recue.length === attendue.length && timingSafeEqual(recue, attendue);
}
En PHP, l'équivalent est hash_equals(hash_hmac('sha256', $corps, $secret), $signatureRecue).
Le HMAC est partout, souvent sans qu'on le nomme :
| Usage | Rôle du HMAC |
|---|---|
| Webhooks (paiement en ligne, dépôts Git), signature des requêtes d'API | Prouver que la requête vient du partenaire et n'a pas été modifiée |
| Jetons JWT signés en HS256 | Rendre le jeton infalsifiable par le client |
| Codes à usage unique des applications d'authentification (TOTP, RFC 6238) | Le code est un HMAC de l'heure courante avec un secret partagé lors de l'enrôlement |
SNMPv3, paramètre auth sha | Authentifier l'agent et garantir l'intégrité de chaque message |
| IPsec, TLS 1.2 | Contrôler l'intégrité de chaque paquet (TLS 1.3 utilise des modes authentifiés, et HMAC pour dériver ses clés) |
| Cookies de session signés des frameworks web | Empêcher un utilisateur de modifier son cookie |
Limite du HMAC : la clé est partagée. Le laboratoire peut vérifier que la commande vient de la clinique, mais il ne peut pas le prouver à un tiers : il possède la même clé et aurait pu fabriquer le message lui-même. Pas de non-répudiation.
La signature numérique : hacher, puis signer avec la clé privée
La signature numérique se fait en deux temps : on calcule l'empreinte du document, puis on la transforme avec la clé privée du signataire. Le destinataire recalcule l'empreinte du document reçu et vérifie, avec la clé publique du signataire, que la signature correspond à cette empreinte.
On signe l'empreinte plutôt que le document entier pour une raison pratique : l'asymétrique est lent et ne traite que des données courtes, alors que l'empreinte fait toujours 256 bits, que le document pèse 1 Ko ou 2 Go.
Avec OpenSSL et la paire RSA du chapitre 4 :
# Signer (clé privée)
openssl dgst -sha256 -sign cle-privee.pem -out compte-rendu.sig compte-rendu.pdf
# Vérifier (clé publique)
openssl dgst -sha256 -verify cle-publique.pem -signature compte-rendu.sig compte-rendu.pdf
# Verified OK
# Après modification d'un seul octet du PDF
# Verification failure
Une signature valide garantit trois choses :
- l'intégrité : le document n'a pas changé d'un bit depuis la signature ;
- l'authenticité : il a été signé par le détenteur de la clé privée ;
- la non-répudiation : le signataire ne peut pas nier, puisque lui seul possède la clé privée (à condition qu'elle soit bien protégée et personnelle).
Reste une question : comment savoir que cette clé publique appartient vraiment au biologiste, et pas à un imposteur ? C'est le rôle du certificat, qui lie une clé publique à une identité (chapitre 8).
HMAC ou signature : comment choisir
| Critère | HMAC | Signature numérique |
|---|---|---|
| Cryptographie | Symétrique : une clé secrète partagée | Asymétrique : clé privée pour signer, clé publique pour vérifier |
| Qui peut vérifier | Seulement ceux qui ont la clé (et qui pourraient aussi signer) | Tout le monde, avec la clé publique |
| Intégrité et authenticité | Oui | Oui |
| Non-répudiation | Non | Oui |
| Vitesse | Très rapide | Plus lente |
| Exemples | Webhook, JWT HS256, TOTP, SNMPv3 | Certificat, mise à jour logicielle, PDF signé, commit Git signé, JWT RS256 |
Les jetons JWT : HS256 ou RS256
Un JWT (JSON Web Token, RFC 7519) est un jeton d'authentification au format en-tête.contenu.signature, chaque partie encodée en Base64URL. Le serveur le délivre après connexion ; le client le renvoie à chaque requête dans l'en-tête Authorization: Bearer ….
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDQyIiwicm9sZSI6InBhdGllbnQiLCJleHAiOjE3OTM1NzA0MDB9.-180QvNkB4YaexOEUxT_rooHdUrSUjLS1-VmvC9_gs8
Décodées, les deux premières parties donnent :
{"alg":"HS256","typ":"JWT"}
{"sub":"1042","role":"patient","exp":1793570400}
Deux points à comprendre absolument :
- Le contenu d'un JWT n'est pas chiffré, il est seulement encodé : n'importe qui le lit. On n'y met jamais de donnée confidentielle (résultat d'analyse, mot de passe, numéro de sécurité sociale).
- La signature empêche de le modifier. Si le patient remplace
"role":"patient"par"role":"admin", la signature ne correspond plus et le serveur doit rejeter le jeton.
| Algorithme | Mécanisme | Quand l'utiliser |
|---|---|---|
| HS256 | HMAC-SHA-256 avec un secret partagé | Un seul service émet et vérifie les jetons ; le secret doit être long et aléatoire |
| RS256, ES256, EdDSA | Signature RSA, ECDSA P-256 ou Ed25519 | Un serveur d'authentification émet, plusieurs services vérifient avec la clé publique, sans pouvoir fabriquer de jetons (authentification unique, OpenID Connect) |
Les pièges classiques : accepter "alg":"none" (jeton non signé), laisser le client choisir l'algorithme, utiliser un secret HS256 court (il se trouve par force brute hors ligne à partir d'un seul jeton), oublier de vérifier l'expiration exp ou la limiter mal. Le champ exp est un horodatage Unix : 1793570400 correspond au 1ᵉʳ novembre 2026 à 22 h 00 UTC.
Signer des fichiers, du code et des commits
Signer un fichier avec GPG. GnuPG (GPG) implémente la norme OpenPGP. Pour signer un PDF sans le modifier, on produit une signature détachée :
gpg --armor --detach-sign BD-version-finale.pdf # crée BD-version-finale.pdf.asc
gpg --verify BD-version-finale.pdf.asc BD-version-finale.pdf
# gpg: Good signature from "Éditeur <editeur@exemple.fr>" (« Bonne signature » en français)
Signer du code. Les installeurs Windows sont signés avec un certificat de signature de code (Authenticode), et Windows avertit l'utilisateur quand un exécutable n'est pas signé. Les dépôts de paquets Debian sont signés, et apt refuse un dépôt dont la signature est invalide. Le Secure Boot vérifie la signature de chaque maillon du démarrage (cours Poste de travail).
Signer ses commits Git. Git peut signer avec la clé SSH que tu utilises déjà pour GitHub :
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git commit -S -m "Corrige le calcul de l'expiration des jetons"
GitHub affiche alors le badge Verified à côté du commit : personne ne peut publier un commit en ton nom sans ta clé privée.
Signature électronique et droit : eIDAS
La signature numérique est le mécanisme technique ; la signature électronique est la notion juridique. En droit français, l'article 1366 du Code civil donne à l'écrit électronique la même force probante que l'écrit papier, « sous réserve que puisse être dûment identifiée la personne dont il émane et qu'il soit établi et conservé dans des conditions de nature à en garantir l'intégrité ». L'article 1367 précise que la signature électronique « consiste en l'usage d'un procédé fiable d'identification garantissant son lien avec l'acte auquel elle s'attache ».
Le règlement européen eIDAS (n° 910/2014, modifié en 2024 par le règlement dit eIDAS 2, n° 2024/1183) distingue trois niveaux :
| Niveau | Exigences | Valeur juridique | Exemple |
|---|---|---|---|
| Simple | Toute donnée électronique jointe à un document et servant à signer | Recevable en justice, mais c'est à celui qui s'en prévaut de prouver sa fiabilité | Case cochée, signature tracée à l'écran, nom tapé |
| Avancée | Liée au signataire de façon univoque, permet de l'identifier, sous son contrôle exclusif, détecte toute modification ultérieure | Plus probante ; la fiabilité reste à démontrer | Plateforme de signature avec vérification d'identité et certificat |
| Qualifiée | Avancée, avec un certificat qualifié délivré par un prestataire qualifié, et un dispositif de création qualifié (carte, module matériel) | Présumée fiable (décret n° 2017-1416) : équivalente à une signature manuscrite dans toute l'Union | Carte de signature d'un professionnel, certains actes notariés |
Pour qu'une signature reste vérifiable des années après, on y ajoute un horodatage fourni par une autorité d'horodatage : il prouve que le document existait sous cette forme à une date donnée, avant l'expiration ou la révocation du certificat. Le cours CEJM droit traite la preuve électronique côté juridique.
À l'E7 : comment la notion est demandée
-
L'intérêt d'une signature. Le sujet SLAM 2025 (cas Casterman) prévoit d'enregistrer en base « la signature électronique » GPG du PDF final d'une bande dessinée et demande d'en expliquer l'intérêt pour l'éditeur et pour l'imprimeur. Réponse structurée par les propriétés : l'intégrité (l'imprimeur imprime exactement la version validée, toute modification se verrait), l'authenticité (le fichier vient bien de l'éditeur) et la non-répudiation (en cas de litige, l'éditeur ne peut pas contester avoir validé cette version, et l'imprimeur prouve qu'il a imprimé le fichier signé).
-
Les jetons. Le sujet SLAM 2024 (cas Gsic) intègre une authentification unique par jetons JWT : une développeuse obtient un jeton, fait une pause de 15 minutes, puis reçoit l'erreur
invalid_token,Token verification failed. L'hypothèse attendue : le jeton a expiré (champexp), et il faut le renouveler avec le jeton de rafraîchissement. Un sujet SLAM 2025 (cas Kirassur) fait justifier la durée de validité limitée des jetons d'accès. -
SNMPv3. Le sujet SISR 2025 (cas Blanca) demande les principes du paramètre
auth sha: une authentification par HMAC-SHA, qui garantit que les messages viennent d'un agent qui connaît le secret et qu'ils n'ont pas été modifiés. -
Vérifier une signature avec OpenSSL. Le sujet SISR 2022 (cas CalédoBank) fait signer électroniquement une offre de prêt : l'application hache le PDF en SHA-512 (
openssl dgst -sha512), puis signe l'empreinte avec une clé privée dont le certificat éphémère est délivré par l'autorité de certification de la banque. On te demande la démarche de vérification, à partir des commandes fournies. Elle suit exactement le schéma de ce chapitre :- extraire la clé publique du certificat :
openssl x509 -pubkey -noout -in srvdbapp.crt > cle_publique.pem; - retrouver l'empreinte signée avec cette clé publique :
openssl rsautl -verify -in contrat.sig -pubin -inkey cle_publique.pem -out contrat_verif.dgt; - recalculer l'empreinte du document reçu :
openssl dgst -sha512 -out contrat_recalc.dgt contrat_test.pdf; - comparer :
diff contrat_verif.dgt contrat_recalc.dgtne renvoie rien si les deux empreintes sont identiques. La signature est alors valide : le document n'a pas été modifié et il a bien été signé avec la clé privée liée au certificat. Il reste à vérifier le certificat lui-même (émis par l'autorité de la banque, pas expiré).
La commande
rsautlest dépréciée depuis OpenSSL 3.0 (elle affiche un avertissement mais fonctionne encore ; son remplaçant estopenssl pkeyutl -verifyrecover). Dans une copie, utilise la syntaxe donnée par le dossier documentaire. - extraire la clé publique du certificat :
Pour aller plus loin. L'usage des JWT dans une application (durée de vie, stockage, révocation) est détaillé dans le chapitre Sessions, cookies et JWT, et la valeur juridique de la signature dans le chapitre Preuve et signature électroniques du cours Droit et RGPD.
Exercices
Exercice 1 sur 5 L'empreinte ne suffit pas Réussi À revoir
Un fournisseur envoie chaque soir un fichier de tarifs accompagné de son empreinte SHA-256, dans le même courriel.
- Un attaquant intercepte le courriel. Peut-il modifier les tarifs sans être détecté ? Comment ?
- Le fournisseur et le laboratoire conviennent d'une clé secrète et remplacent l'empreinte par un HMAC-SHA-256. Que change cette mesure ?
- En cas de litige sur un tarif, le laboratoire peut-il prouver au juge que le fournisseur a bien envoyé ce fichier ?
Voir la réponseMasquer la réponse de l'exercice 1
- Oui : il modifie le fichier, recalcule son empreinte SHA-256 (une fonction publique, sans clé) et remplace l'ancienne. Le laboratoire recalcule, trouve la même valeur et ne voit rien.
- L'attaquant ne connaît pas la clé : il ne peut pas calculer le HMAC du fichier modifié. Toute modification est détectée ; l'intégrité et l'authenticité sont garanties entre les deux partenaires.
- Non : le laboratoire possède la même clé et aurait pu fabriquer le fichier et son HMAC. Pour la non-répudiation, il faut une signature avec la clé privée du fournisseur, vérifiable avec sa clé publique certifiée.
Tu avais trouvé ?
Exercice 2 sur 5 Qui fait quoi avec quelle clé ? Réussi À revoir
Le biologiste Paul signe un compte rendu ; le docteur Leroy le vérifie.
- Avec quelle clé Paul signe-t-il ?
- Avec quelle clé le docteur Leroy vérifie-t-il, et où la trouve-t-il ?
- Le docteur Leroy recalcule l'empreinte et constate qu'elle ne correspond pas à la signature. Que peut-il conclure ?
Voir la réponseMasquer la réponse de l'exercice 2
- Avec la clé privée de Paul, après avoir calculé l'empreinte du document.
- Avec la clé publique de Paul, qu'il trouve dans le certificat de Paul, délivré par une autorité de certification en laquelle il a confiance.
- Le document a été modifié après la signature, ou la signature n'a pas été faite avec la clé privée de Paul. Dans les deux cas, il ne doit pas se fier au document.
Tu avais trouvé ?
Exercice 3 sur 5 Lire un jeton Réussi À revoir
Un patient se connecte au portail et reçoit ce jeton :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDQyIiwicm9sZSI6InBhdGllbnQiLCJleHAiOjE3OTM1NzA0MDB9.-180QvNkB4YaexOEUxT_rooHdUrSUjLS1-VmvC9_gs8
- Quel algorithme protège le jeton ?
- Que contient la deuxième partie, et le patient peut-il la lire ?
- Il remplace
patientparadminet réencode la deuxième partie. Que doit faire le serveur, et pourquoi ? - Un développeur propose d'ajouter au jeton le dernier résultat d'analyse du patient « pour éviter une requête ». Ton avis ?
Voir la réponseMasquer la réponse de l'exercice 3
- HS256, c'est-à-dire un HMAC-SHA-256 avec un secret connu du seul serveur (en-tête
{"alg":"HS256","typ":"JWT"}). {"sub":"1042","role":"patient","exp":1793570400}: l'identifiant du patient, son rôle et la date d'expiration (1ᵉʳ novembre 2026, 22 h 00 UTC). Oui, il la lit : c'est du Base64URL, pas du chiffrement.- Rejeter le jeton : la signature a été calculée sur le contenu d'origine ; le contenu modifié ne correspond plus, et le patient ne peut pas recalculer la signature sans le secret du serveur.
- À refuser : le contenu d'un JWT est lisible par quiconque intercepte ou récupère le jeton (journaux, historique, poste partagé). Un résultat d'analyse est une donnée de santé : il reste sur le serveur et ne s'obtient qu'après vérification du jeton.
Tu avais trouvé ?
Exercice 4 sur 5 Expliquer l'intérêt d'une signature Réussi À revoir
Le laboratoire envoie chaque mois à l'Assurance maladie un fichier de facturation. On décide de le signer avec une clé privée dont le certificat a été délivré par une autorité reconnue. Explique, en citant les propriétés de sécurité, l'intérêt de cette signature pour le laboratoire et pour le destinataire.
Voir la réponseMasquer la réponse de l'exercice 4
Pour le destinataire : l'intégrité (le fichier n'a pas été modifié en route, par exemple un montant ou un numéro de patient) et l'authenticité (il vient bien du laboratoire, pas d'un fraudeur qui imiterait son adresse d'envoi).
Pour le laboratoire : la non-répudiation joue dans les deux sens. Le laboratoire ne peut pas contester avoir envoyé ce fichier, et il peut prouver ce qu'il a réellement envoyé si le destinataire conteste un montant : toute version différente ne correspondrait pas à la signature. Avec un horodatage, il prouve aussi la date d'envoi.
Tu avais trouvé ?
Exercice 5 sur 5 HMAC ou signature ? Réussi À revoir
Choisis le mécanisme et justifie.
- Le serveur de paiement prévient l'application du laboratoire qu'une facture a été réglée.
- L'éditeur d'un logiciel publie une mise à jour téléchargée par des milliers de clients.
- Un service d'authentification émet des jetons vérifiés par cinq applications internes.
- Un contrat avec un prestataire doit avoir valeur de preuve.
Voir la réponseMasquer la réponse de l'exercice 5
- HMAC : deux systèmes qui partagent un secret, il suffit de vérifier l'intégrité et l'origine de la notification.
- Signature : des milliers de clients doivent vérifier, il est hors de question de leur donner une clé secrète qui leur permettrait de fabriquer de fausses mises à jour. Ils vérifient avec la clé publique de l'éditeur.
- Signature (RS256, ES256) : les cinq applications vérifient avec la clé publique sans pouvoir émettre de jetons. Avec un HMAC, chacune détiendrait le secret et pourrait fabriquer des jetons valables pour les autres.
- Signature électronique, de niveau avancé ou qualifié selon l'enjeu : seule une clé personnelle apporte la non-répudiation, et la signature qualifiée bénéficie d'une présomption de fiabilité.
Tu avais trouvé ?