Aller au contenu

Condensés cryptographiques : propriétés, constructions et familles

Condensés cryptographiques : propriétés, constructions et familles

Section intitulée « Condensés cryptographiques : propriétés, constructions et familles »

Une fonction de hachage cryptographique transforme une donnée de taille quelconque en une empreinte courte et de taille fixe, le condensé (en anglais digest ou hash). C’est la primitive la plus utilisée et la plus mal comprise de la discipline : elle sert à vérifier l’intégrité d’un fichier, à construire des MAC (Message Authentication Code, code d’authentification de message), des signatures, des arbres de preuves et des dérivations de clés, mais elle ne chiffre rien, n’authentifie personne à elle seule et protège très mal un mot de passe. Ce chapitre détaille ses propriétés, la façon dont on la construit, les familles en usage et celles qu’il faut laisser au musée.

→ Lire l’explication complète de la marmotte

Quatre propriétés de base définissent l’objet. La sortie a une taille fixe : SHA-256 rend toujours 256 bits, que l’entrée fasse trois octets ou trois téraoctets. Le calcul est déterministe : la même entrée donne toujours le même condensé, sur toutes les machines, ce qui permet à deux parties de comparer leurs résultats sans s’échanger les données. Il n’y a pas de clé : n’importe qui peut calculer le condensé de n’importe quoi. Enfin, l’effet d’avalanche fait qu’une modification d’un seul bit en entrée change environ la moitié des bits de sortie, sans motif exploitable.

Fenêtre de terminal
printf 'abc' | sha256sum
# ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
printf 'abd' | sha256sum
# a52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9

Une lettre de différence, deux empreintes sans rien en commun. C’est ce qui fait du condensé un outil de vérification d’intégrité : un éditeur publie l’empreinte d’une image disque, l’utilisateur recalcule la sienne et compare.

Fenêtre de terminal
sha256sum debian.iso > debian.iso.sha256 # côté éditeur
sha256sum -c debian.iso.sha256 # côté utilisateur : "debian.iso: OK"

La limite saute aux yeux dès qu’on y pense : si l’attaquant peut remplacer le fichier, il peut aussi remplacer l’empreinte publiée à côté. Le condensé prouve que deux données sont identiques, pas qui les a produites. Pour cela, il faut une clé, donc un MAC ou une signature.

On ne « déchiffre » pas un condensé, pour une raison de simple comptage : une infinité d’entrées possibles se partagent 2^256 sorties, l’information perdue ne se retrouve pas. Les « sites de déchiffrement de hash » ne font qu’interroger des tables d’empreintes précalculées : ils retrouvent motdepasse parce que quelqu’un l’a haché avant, pas parce qu’ils ont inversé quoi que ce soit. C’est d’ailleurs tout le problème des mots de passe : l’espace des mots de passe humains est petit, et une fonction conçue pour être rapide permet de le parcourir à grande vitesse. Un seul passage de SHA-256 sur un mot de passe, même salé, laisse une carte graphique tester des milliards de candidats par seconde. Le stockage des mots de passe relève de fonctions lentes et gourmandes en mémoire comme Argon2id, traitées dans Transformer mots de passe et secrets applicatifs en clés.

Pour une fonction à sortie de n bits, trois propriétés sont attendues, avec un coût d’attaque générique différent.

PropriétéL’attaquant doit trouverCoût générique
Résistance à la préimageune entrée x telle que H(x) = h imposé2^n
Résistance à la seconde préimagex’ ≠ x tel que H(x’) = H(x), x étant donné2^n
Résistance aux collisionsdeux entrées quelconques x ≠ x’ de même condensé2^(n/2)

La collision est la plus facile parce que l’attaquant choisit les deux entrées : c’est le paradoxe des anniversaires. Dans une classe de 23 élèves, la probabilité que deux d’entre eux partagent un anniversaire dépasse 50 %, alors qu’il n’y a que 365 dates. De même, après environ 2^(n/2) condensés calculés, une collision devient probable. Pour SHA-256, cela donne 2^128 opérations, hors de portée ; pour un condensé tronqué à 64 bits, 2^32, soit environ quatre milliards de calculs, l’affaire de quelques minutes sur un ordinateur portable.

L’impact d’une cassure dépend donc de la propriété touchée. Une collision permet de faire signer un document anodin puis de présenter son jumeau malveillant, à condition que l’attaquant fabrique les deux. Une seconde préimage permet de falsifier un document existant qu’il n’a pas choisi, ce qui est bien plus grave. Croire que toute collision théorique a le même impact est une erreur dans les deux sens : MD5 reste inutilisable pour les signatures, mais aucune préimage pratique n’est connue sur MD5, et une ancienne empreinte MD5 d’un fichier publié avant les attaques n’est pas soudain falsifiable.

Une quatrième exigence, plus floue, apparaît dès qu’on compose : l’imprévisibilité. Dans un HMAC, une dérivation de clés ou une signature, on attend que la sortie se comporte comme une fonction aléatoire. Cette idéalisation, le modèle de l’oracle aléatoire, sert aux preuves de sécurité, mais aucune fonction réelle ne l’est. Les écarts sont parfois structurels, comme l’extension de longueur décrite plus bas.

Une fonction de hachage traite les longues entrées par morceaux, en itérant une petite fonction de compression qui prend un état interne et un bloc de message et rend un nouvel état.

La construction Merkle-Damgård, employée par MD5, SHA-1 et SHA-2, procède ainsi : le message est complété (le padding) par un bit à 1, des zéros, puis la longueur du message d’origine, jusqu’à un multiple de la taille de bloc (512 bits pour SHA-256). L’état part d’une valeur initiale fixe, chaque bloc est compressé dans l’état, et l’état final est le condensé. Inclure la longueur dans le padding garantit qu’une collision sur la fonction entière implique une collision sur la compression.

Cette élégance a un défaut : le condensé publié est l’état interne final. Quiconque connaît H(m) et la longueur de m peut reprendre le calcul là où il s’est arrêté et obtenir H(m ‖ padding ‖ suffixe) sans connaître m. C’est l’attaque par extension de longueur. Elle ruine la construction naïve MAC = SHA-256(clé ‖ message) : l’attaquant qui voit un message signé montant=10 et son tag peut produire un tag valide pour montant=10[padding]&montant=10000, sans la clé. Des outils publics comme hash_extender automatisent la manœuvre. Le remède est le HMAC (RFC 2104), qui imbrique deux appels avec des clés dérivées, ou une fonction non vulnérable. Les variantes tronquées SHA-384 et SHA-512/256 n’exposent pas leur état complet et résistent à cette attaque, tout comme SHA-3 et BLAKE2.

Autre propriété contre-intuitive des constructions itératives, les multicollisions (Joux, 2004) : trouver 2^k messages ayant le même condensé ne coûte qu’environ k fois le prix d’une collision. Conséquence pratique : concaténer MD5(x) ‖ SHA-1(x), soit 288 bits de sortie, ne donne pas les 144 bits de résistance aux collisions qu’on attendrait d’une sortie de cette taille, mais à peine plus que la plus forte des deux fonctions prise seule.

La construction éponge (sponge), retenue pour SHA-3, abandonne la compression au profit d’une grosse permutation publique appliquée à un état de 1600 bits pour Keccak. L’état est découpé en deux zones : le débit (rate, r bits), où le message est injecté puis où la sortie est lue, et la capacité (c bits), jamais exposée directement. Pour SHA3-256, r = 1088 et c = 512. Phase d’absorption : chaque bloc est combiné par XOR dans le débit, puis la permutation brasse tout l’état. Phase d’essorage : on lit le débit, on permute, on relit, autant que nécessaire. La sécurité générique est bornée par c/2, d’où une capacité double du niveau visé. Puisque la capacité reste cachée, l’extension de longueur est impossible. En revanche, la permutation est inversible : une fuite de l’état complet, par exemple via un canal auxiliaire, permet de remonter les calculs et compromet tout ce qui en dépend. Une éponge protège ce qu’elle ne montre pas, encore faut-il qu’elle ne le montre pas.

L’essorage illimité donne naturellement une XOF (eXtendable-Output Function, fonction à sortie extensible) : on demande 32, 64 ou 1000 octets de sortie. SHAKE128 et SHAKE256 en sont les représentants normalisés. Une XOF n’offre pas plus de sécurité que sa capacité le permet : SHAKE128 tiré sur 512 bits reste plafonné à 128 bits de sécurité.

Reste la séparation de domaine : quand une même fonction sert à plusieurs usages, chaque usage doit préfixer ses entrées d’une étiquette distincte, faute de quoi une valeur calculée dans un contexte peut être rejouée dans un autre. L’exemple canonique est l’arbre de Merkle de Certificate Transparency (RFC 6962), qui hache les feuilles sous le préfixe 0x00 et les nœuds internes sous 0x01 : sans cela, un nœud interne pourrait être présenté comme une feuille. SHA-3 réserve des bits de padding différents pour SHA3 et SHAKE, et cSHAKE ou Ascon-CXOF128 acceptent une chaîne de personnalisation prévue à cet effet.

SHA-2 (FIPS 180-4) regroupe SHA-224, SHA-256, SHA-384, SHA-512 et les variantes SHA-512/224 et SHA-512/256. C’est le choix par défaut, universellement disponible et accéléré par des instructions matérielles sur les processeurs récents. Aucune attaque pratique ne la menace ; seule l’extension de longueur impose d’utiliser HMAC plutôt qu’une construction maison.

SHA-3 (FIPS 202, 2015) est issue du concours remporté par Keccak. Ce n’est pas un remplaçant de SHA-2 en urgence mais une alternative de structure différente, utile en cas de mauvaise surprise et pour ses XOF SHAKE.

BLAKE2 (RFC 7693) est très rapide en logiciel, offre un mode à clé natif qui fait office de MAC, et sert par exemple dans Argon2 et WireGuard. BLAKE3 (2020) organise le calcul en arbre, ce qui le rend parallélisable sur tous les cœurs disponibles, et propose trois modes : hachage, hachage à clé et dérivation de clé à partir d’une chaîne de contexte. Ce dernier mode est une KDF (Key Derivation Function, fonction de dérivation de clé) pour des secrets déjà aléatoires : BLAKE3 est volontairement rapide et ne doit jamais servir à dériver une clé depuis un mot de passe.

Ascon, lauréat du concours de cryptographie légère du NIST (National Institute of Standards and Technology), est normalisé dans le SP 800-232 sous la forme d’Ascon-Hash256, d’Ascon-XOF128 et d’Ascon-CXOF128, cette dernière ajoutant une chaîne de personnalisation pour la séparation de domaine. Son état de 320 bits le destine aux microcontrôleurs et objets contraints, où SHA-3 et ses 1600 bits pèsent trop lourd.

SHA-1 est cassé pour les collisions depuis 2017 (première collision publique, SHAttered) et pour les collisions à préfixe choisi depuis 2020, ce qui permet de fabriquer de faux certificats ou de fausses signatures PGP. Le NIST a annoncé en 2022 son retrait de tous les usages d’ici fin 2030. Il subsiste dans des usages où les collisions ne sont pas le sujet, comme les identifiants d’objets de Git, qui intègre une détection de collisions, ou HMAC-SHA1, dont la sécurité repose sur d’autres propriétés. Pour tout nouveau développement, il n’a rien à faire.

MD5 est cassé pour les collisions depuis 2004 ; en 2012, le maliciel Flame a utilisé une collision MD5 à préfixe choisi pour se doter d’un certificat de signature de code présenté comme émanant de Microsoft. MD4 est encore plus faible et survit pourtant au cœur de l’empreinte NT des mots de passe Windows, voir NTLM : fonctionnement, vulnérabilités et durcissement. MD2, HAVAL, Snefru et N-Hash sont des fonctions des années 1990, cassées ou abandonnées, qui n’intéressent plus que les historiens et les inventaires de code ancien. RIPEMD-160 n’est pas cassé mais n’est plus recommandé pour du neuf ; il reste connu pour son rôle dans les adresses Bitcoin.

Calculer et vérifier un condensé avec plusieurs familles :

Fenêtre de terminal
openssl dgst -sha3-256 fichier.bin
openssl dgst -shake256 -xoflen 64 fichier.bin # XOF : 64 octets demandés
b3sum fichier.bin # BLAKE3, si l'outil est installé

Construire un mini arbre de Merkle avec séparation de domaine, qui permet ensuite de prouver qu’un élément appartient à l’ensemble en ne fournissant que log2(n) condensés :

import hashlib
def feuille(d): return hashlib.sha256(b"\x00" + d).digest()
def noeud(g, d): return hashlib.sha256(b"\x01" + g + d).digest()
f = [feuille(x) for x in (b"a", b"b", b"c", b"d")]
racine = noeud(noeud(f[0], f[1]), noeud(f[2], f[3]))
print(racine.hex())
# Preuve que "c" est dans l'arbre : f[3] et noeud(f[0], f[1])

Classer les fonctions selon l’usage donne un tableau à garder sous la main :

FonctionStatutRemarque
SHA-256, SHA-512, SHA-384moderneHMAC obligatoire pour authentifier
SHA3-256, SHAKE256modernepas d’extension de longueur
BLAKE2b, BLAKE3modernemode à clé et dérivation intégrés
Ascon-Hash256, Ascon-XOF128moderne, contraintobjets et microcontrôleurs
SHA-1dépréciécollisions pratiques, retrait fin 2030
MD5, MD4, MD2historiqueà recenser et à remplacer

Pour comparer SHAKE, BLAKE3 et Ascon-XOF : SHAKE est la XOF normalisée de référence, disponible partout où SHA-3 l’est ; BLAKE3 est la plus rapide sur un processeur généraliste grâce à son arbre parallèle, mais n’est pas une norme fédérale américaine, ce qui compte dans certains appels d’offres ; Ascon-XOF128 vise le plus petit encombrement en mémoire et en silicium, au prix d’un débit modeste sur un serveur.

Utiliser SHA-256 seul pour un mot de passe donne une base qui, une fois volée, se casse au rythme du matériel de l’attaquant. Utiliser hash(clé ‖ message) comme MAC ouvre la porte à l’extension de longueur avec toute la famille SHA-2 non tronquée. Oublier la séparation de domaine permet de confondre une feuille et un nœud, un jeton de session et un jeton de réinitialisation. Et lire « collision trouvée » comme « tout est perdu », ou à l’inverse « seulement une collision » comme « rien de grave », revient à ignorer quelle propriété est touchée et dans quel usage.

Un hash est calculable par tous ; un MAC exige une clé secrète partagée et prouve que le message vient de quelqu’un qui la détient, voir Prouver qu’un message vient du bon secret. Un hash de fichier atteste l’identité de deux copies ; une signature atteste qu’un détenteur de clé privée a approuvé ce contenu, voir Signer numériquement. Une collision porte sur deux entrées choisies librement ; une préimage vise une sortie imposée. BLAKE3 en mode dérivation est une KDF rapide pour secrets aléatoires, pas une fonction de hachage de mots de passe. Les usages systèmes, arbres, journaux et preuves d’inclusion, sont développés dans Hachage dans les systèmes.

Choisir mal son condensé, ou l’employer hors de son rôle, ouvre des brèches silencieuses. Avec une famille dont les collisions sont connues, deux documents différents peuvent porter la même empreinte : celui qui a été vérifié et celui qui sera réellement utilisé. Une construction hash(key || message) laisse, avec les fonctions sensibles à l’extension de longueur, fabriquer un message prolongé portant une empreinte valide sans connaître la clé. Et une base de mots de passe hachés d’un seul passage de SHA-256 se retrouve, une fois volée, attaquée hors ligne au rythme du matériel de l’attaquant, sans verrou ni journal pour le ralentir.

Une fonction de hachage prend une donnée de n’importe quelle taille et produit une sortie de taille fixe, appelée condensé. Le calcul est déterministe : la même entrée donne toujours la même sortie. Changer un seul bit de l’entrée bouleverse la sortie, c’est l’effet d’avalanche. Il n’y a pas de clé : n’importe qui peut calculer le condensé. On ne peut pas « déchiffrer » un condensé, car une grande partie de l’information a été perdue. Trois propriétés comptent. Il doit être impossible en pratique de trouver une entrée qui donne un condensé imposé, de trouver une seconde entrée ayant le même condensé qu’une entrée connue, et de trouver deux entrées quelconques ayant le même condensé, ce qu’on appelle une collision. Cette dernière est la plus facile à attaquer, car les chances de réussite augmentent vite avec le nombre d’essais. Pour traiter une longue donnée, la fonction la découpe en morceaux et les mélange pas à pas. Certaines constructions anciennes permettent de prolonger un message sans connaître son début ; c’est pourquoi hacher une clé collée devant un message ne constitue pas une authentification sûre. Les familles SHA-2, SHA-3 et BLAKE sont utilisées aujourd’hui ; MD5 et SHA-1 sont dépassées. Enfin, hacher un mot de passe une seule fois est trop rapide : un attaquant peut essayer très vite un grand nombre de mots de passe. Il faut des fonctions conçues pour ce cas.

À lire aussi

Pages voisines

: les deux pages se citent l’une l’autre.