Les fonctions de hachage sont partout dans le développement logiciel, même si vous ne le réalisez pas. Chaque fois que vous téléchargez un fichier et vérifiez son checksum, vous connectez à un site web, faites un commit Git, ou minez du Bitcoin (bon, peut-être pas ce dernier), les fonctions de hachage font le gros du travail en coulisses.

Comprenons ce qu'elles sont, comment elles diffèrent, et laquelle utiliser selon le cas.

Qu'est-ce qu'une fonction de hachage ?

Une fonction de hachage prend n'importe quelle entrée — un seul caractère, un roman, un fichier vidéo de 4 Go — et produit une sortie de taille fixe appelée « hash » ou « digest ». C'est comme une empreinte digitale pour les données. Quelle que soit la taille de l'entrée, la sortie a toujours la même longueur.

Voici ce qui rend les fonctions de hachage spéciales :

  • Déterministe : La même entrée donne toujours la même sortie. hash("hello") retournera la même valeur à chaque fois, sur n'importe quelle machine, dans n'importe quel langage de programmation.
  • Sens unique : Impossible de retrouver l'entrée à partir de la sortie. Étant donné un hash, il n'y a aucun moyen de découvrir ce qui l'a produit (à part deviner). C'est ce qui les rend utiles pour stocker des mots de passe.
  • Effet avalanche : Changez un seul bit de l'entrée et la sortie change radicalement. Par exemple, les hashes SHA-256 de « hello » et « Hello » sont des chaînes complètement différentes.
  • Résistance aux collisions : Il devrait être pratiquement impossible de trouver deux entrées différentes qui produisent le même hash. Plus l'algorithme est fort, plus les collisions sont difficiles à trouver.

Voyons cela en action :

plaintext

Des sorties totalement différentes à partir d'entrées qui ne diffèrent que d'un seul caractère — un « h » minuscule contre un « H » majuscule. C'est l'effet avalanche en action.

Comment fonctionnent les fonctions de hachage sous le capot

Bien que les mathématiques derrière les fonctions de hachage soient complexes, le processus général est simple. La plupart des fonctions de hachage suivent ces étapes :

1. Bourrage (Padding) : Le message d'entrée est complété pour que sa longueur devienne un multiple d'une taille de bloc fixe (par exemple, 512 bits pour SHA-256). Cela garantit que l'algorithme peut traiter les données en blocs uniformes.

2. Découpage en blocs : Le message complété est divisé en blocs de taille fixe.

3. Rondes de compression : Chaque bloc est traité à travers plusieurs rondes d'opérations bit à bit — XOR, AND, OR, décalages de bits et addition modulaire. Ces opérations mélangent les bits de manière approfondie pour que chaque bit de sortie dépende de chaque bit d'entrée.

4. Chaînage : La sortie du traitement d'un bloc alimente le traitement du bloc suivant. C'est pourquoi même un changement minuscule au début de l'entrée se propage en cascade à travers chaque bloc suivant.

5. Digest final : Après le traitement de tous les blocs, l'état interne est émis comme valeur de hachage finale.

L'idée clé est que ces opérations sont faciles à calculer dans un sens mais pratiquement impossibles à inverser. On ne peut pas « démélanger » les bits pour retrouver l'entrée originale.

MD5 : Le vétéran à la retraite

MD5 a été conçu par Ronald Rivest en 1991 et produit un hash de 128 bits (32 caractères hexadécimaux). C'était la référence pendant des décennies — on voyait des checksums MD5 à côté de chaque téléchargement de fichier sur internet.

Cependant, MD5 est maintenant considéré comme cryptographiquement cassé. Des chercheurs ont démontré des attaques par collision pratiques — c'est-à-dire qu'ils peuvent créer deux fichiers différents qui produisent le même hash MD5. En 2008, des chercheurs ont utilisé une collision MD5 pour créer un faux certificat SSL, prouvant que ce n'était pas qu'une faiblesse théorique.

Encore acceptable pour : les vérifications d'intégrité de fichiers (confirmer qu'un téléchargement s'est terminé correctement), les checksums pour la déduplication, les tables de hachage non liées à la sécurité, et l'empreinte rapide de données lorsque la sécurité n'est pas une préoccupation.

Jamais pour : le stockage de mots de passe, les signatures numériques, les certificats de sécurité, ou tout ce où quelqu'un pourrait délibérément créer des collisions.

SHA-1 : Également à la retraite

SHA-1 a été conçu par la NSA et publié en 1995. Il produit un hash de 160 bits (40 caractères hexadécimaux). Pendant des années, c'était le standard pour les certificats SSL, les signatures PGP et les systèmes de contrôle de version.

Il est devenu obsolète après que Google ait démontré une attaque par collision pratique en 2017 (la fameuse attaque SHAttered). Ils ont créé deux fichiers PDF différents avec le même hash SHA-1. L'attaque a nécessité 9 223 372 036 854 775 808 calculs SHA-1 — énorme, mais faisable avec les ressources modernes du cloud computing.

Git utilise toujours SHA-1 en interne pour les hashes de commits, mais migre vers SHA-256. Les navigateurs et les autorités de certification ont cessé d'accepter les certificats SHA-1 il y a des années. Si vous voyez SHA-1 utilisé pour la sécurité dans un code aujourd'hui, il devrait être signalé et migré.

SHA-256 et SHA-512 : Les standards actuels

Ils font partie de la famille SHA-2, conçue par la NSA et publiée en 2001. C'est ce que vous devriez utiliser aujourd'hui pour la plupart des cas.

  • SHA-256 : Sortie de 256 bits (64 caractères hex). Utilisé dans Bitcoin, les certificats TLS et la plupart des applications de sécurité. C'est le parfait équilibre entre sécurité et performance. Le système entier de preuve de travail de Bitcoin repose sur le double hachage SHA-256.
  • SHA-512 : Sortie de 512 bits (128 caractères hex). Une sortie plus grande signifie plus de résistance aux collisions. Fait intéressant, SHA-512 est souvent plus rapide que SHA-256 sur les processeurs 64 bits car il opère nativement sur des mots de 64 bits, tandis que SHA-256 utilise des mots de 32 bits.
  • SHA-384 et SHA-512/256 : Ce sont des variantes tronquées de SHA-512. SHA-384 donne une sortie de 384 bits, tandis que SHA-512/256 donne une sortie de 256 bits mais avec les avantages de performance des opérations 64 bits de SHA-512.

Comparaison rapide :

plaintext

SHA-3 : La prochaine génération

SHA-3 a été standardisé en 2015 après un concours public organisé par le NIST. Contrairement à SHA-2, qui utilise une construction Merkle-Damgard, SHA-3 est basé sur la construction éponge Keccak — un design fondamentalement différent.

Pourquoi est-ce important ? Si une percée mathématique venait à compromettre l'approche de conception de SHA-2, SHA-3 ne serait pas affecté car il fonctionne de manière complètement différente. C'est une police d'assurance pour la communauté cryptographique.

SHA-3 existe dans les mêmes tailles de sortie — SHA3-256, SHA3-384, SHA3-512 — et introduit également SHAKE128 et SHAKE256, des « fonctions de sortie extensible » qui peuvent produire un hash de n'importe quelle longueur souhaitée.

En pratique, SHA-2 reste plus largement utilisé et plus rapide sur la plupart du matériel. L'adoption de SHA-3 progresse, mais c'est plutôt un standard de secours qu'un remplacement.

Cas d'utilisation concrets

Contrôle de version Git : Chaque commit, arbre et blob dans Git est identifié par son hash SHA-1. Quand vous exécutez git commit, Git hache le contenu de vos modifications, la structure de l'arbre, le hash du commit parent, vos informations d'auteur et l'horodatage. C'est pourquoi les hashes de commits ressemblent à a1b2c3d4e5f6... — ce sont littéralement des digests SHA-1.

Minage de Bitcoin : Les mineurs rivalisent pour trouver une valeur nonce qui, combinée aux données du bloc et hachée avec un double SHA-256, produit un hash inférieur à un seuil cible. La difficulté de trouver ce hash est ce qui sécurise l'ensemble du réseau. En 2024, le réseau Bitcoin calcule environ 500 trillions de hashes SHA-256 par seconde.

Déduplication de fichiers : Les services de stockage cloud comme Dropbox hachent chaque fichier que vous téléchargez. Si le hash correspond à un fichier existant, ils ne stockent pas de doublon — ils ajoutent simplement un pointeur. Cela économise d'énormes quantités de stockage.

Signatures numériques : Quand vous signez un document ou une version logicielle, vous ne signez pas le fichier entier. À la place, le fichier est haché, et c'est le hash qui est signé avec votre clé privée. Le destinataire hache le fichier de son côté et vérifie la signature par rapport à ce hash.

Authentification d'API : HMAC (Code d'Authentification de Message basé sur le Hachage) combine une clé secrète avec un hash du message pour vérifier à la fois l'intégrité et l'authenticité des requêtes API. AWS, Stripe et la plupart des grandes APIs utilisent HMAC-SHA256 pour la signature des requêtes.

Erreurs courantes des développeurs avec le hachage

Utiliser des fonctions de hachage pour les mots de passe : Le SHA-256 simple est trop rapide pour le hachage de mots de passe. Un attaquant avec un GPU peut calculer des milliards de hashes SHA-256 par seconde, rendant les attaques par force brute triviales. Utilisez toujours des fonctions de hachage de mots de passe dédiées comme bcrypt, scrypt ou Argon2, qui sont intentionnellement lentes et gourmandes en mémoire.

Ne pas utiliser de sel (salt) : Si vous hachez des mots de passe sans sel (une valeur aléatoire ajoutée à chaque mot de passe avant le hachage), des mots de passe identiques produisent des hashes identiques. Un attaquant avec une « rainbow table » précalculée peut retrouver les mots de passe courants instantanément. Ajoutez toujours un sel unique et aléatoire par utilisateur.

Comparer les hashes de manière non sécurisée en temps : Utiliser == pour comparer des hashes dans du code sensible à la sécurité peut divulguer des informations via des canaux latéraux de temporisation. Un attaquant peut mesurer le temps de comparaison et déduire le hash caractère par caractère. Utilisez des fonctions de comparaison en temps constant comme crypto.timingSafeEqual() en Node.js ou hmac.compare_digest() en Python.

Tronquer les hashes : Certains développeurs tronquent les hashes pour économiser de l'espace (par exemple, ne stocker que les 16 premiers caractères d'un hash SHA-256). Cela réduit considérablement la résistance aux collisions. Un hash SHA-256 complet a 2^256 valeurs possibles ; le tronquer à 16 caractères hexadécimaux ne laisse que 2^64 — un nombre que le matériel moderne peut forcer par force brute.

Quelle fonction de hachage utiliser ?

  • Intégrité des fichiers (non-sécurité) : SHA-256 ou même MD5 convient. Vous vérifiez la corruption accidentelle, pas la manipulation malveillante.
  • Stockage de mots de passe : Aucune de celles-ci ! Utilisez bcrypt, scrypt ou Argon2 — ils sont volontairement lents, ce qui rend les attaques par force brute impraticables. Les fonctions de hachage classiques sont trop rapides pour le hachage de mots de passe.
  • Signatures numériques et certificats : SHA-256 ou SHA-512.
  • HMAC (authentification de messages) : SHA-256 ou SHA-512.
  • Adressage de contenu style Git : SHA-256 (la direction que prend Git).
  • Pérennité : Si vous construisez un système qui doit durer des décennies et voulez un plan de secours au cas où SHA-2 serait compromis, envisagez SHA-3.
  • Checksums dans les pipelines de données : SHA-256 pour la vérification d'intégrité des données entre les étapes du pipeline. CRC32 est plus rapide mais ne détecte que les erreurs accidentelles, pas la manipulation intentionnelle.

Fonctions de hachage en code : Exemples pratiques

Bon, assez de théorie — écrivons du code. Parce qu'honnêtement, la meilleure façon de comprendre le hachage, c'est simplement... de le faire. Voici comment calculer des hashes dans les langages que vous utilisez probablement tous les jours.

Node.js — Le module crypto intégré rend cela vraiment simple :

javascript

Et voici le truc cool — hacher un fichier, c'est quasiment la même chose :

javascript

Python — Le hashlib de Python est tout aussi simple. Je trouve d'ailleurs que Python a la plus belle API pour ça :

python

Go — La bibliothèque standard de Go est incroyablement bien conçue pour ça :

go

Java — Un peu plus verbeux (parce que... Java), mais ça marche très bien :

java

Vérifier un téléchargement de fichier : C'est l'un des usages les plus pratiques du hachage. Disons que vous téléchargez un ISO Linux et que le site web indique que le checksum SHA-256 devrait être abc123.... Voici comment le vérifier :

bash

Je sais que ça paraît basique, mais vous seriez surpris du nombre de développeurs qui sautent cette étape. Un seul octet corrompu dans un téléchargement de 4 Go peut vous gâcher tout l'après-midi.

Les Rainbow Tables et pourquoi elles sont terrifiantes

OK, voici la partie qui m'a scotché quand je l'ai apprise pour la première fois. Imaginez que quelqu'un précalcule le hash de chaque mot de passe possible jusqu'à, disons, 8 caractères. Chaque combinaison de lettres, chiffres et symboles. Ils stockent toutes ces correspondances hash-vers-mot-de-passe dans une table de recherche géante.

Ça, c'est une rainbow table. Et elles sont absolument terrifiantes.

Voici pourquoi : si vous avez stocké des mots de passe sous forme de hashes SHA-256 simples (sans sel), un attaquant qui obtient votre base de données n'a rien besoin de « craquer ». Il cherche simplement chaque hash dans sa rainbow table. Boum — récupération instantanée du mot de passe. La recherche prend des microsecondes.

Quelle taille font ces tables ? Une rainbow table couvrant tous les mots de passe alphanumériques jusqu'à 8 caractères peut faire environ 100 à 200 Go. Ça semble beaucoup, mais ça tient sur un seul SSD. Des sites comme CrackStation ont des tables avec des milliards de hashes précalculés, et ils craquent les hashes de mots de passe courants en quelques secondes gratuitement.

Maintenant, la bonne nouvelle : le salage défait complètement les rainbow tables. Un sel est simplement une chaîne aléatoire que vous ajoutez au mot de passe avant de le hacher :

plaintext

Vous voyez ce qui s'est passé ? Le même mot de passe ("password123") produit des hashes complètement différents à cause des sels différents. Un attaquant devrait construire une rainbow table séparée pour chaque sel possible, ce qui est informatiquement impossible.

Toute bibliothèque moderne de hachage de mots de passe (bcrypt, Argon2, scrypt) gère le salage automatiquement. Si jamais vous êtes tenté de créer votre propre hachage de mots de passe — ne le faites pas. Sérieusement. Utilisez bcrypt et passez à autre chose.

HMAC : Hacher avec un secret

HMAC signifie Code d'Authentification de Message basé sur le Hachage, et je sais, je sais, ça semble intimidant. Mais restez avec moi — c'est en fait un concept assez simple que vous avez probablement déjà utilisé sans le savoir.

Le hachage classique prend un message et produit un hash. HMAC prend un message ET une clé secrète, et produit un hash. La différence clé (jeu de mots voulu) est que seul quelqu'un qui connaît la clé secrète peut produire ou vérifier le HMAC. Cela prouve deux choses à la fois : le message n'a pas été altéré, ET il provient de quelqu'un qui connaît le secret.

Où voit-on ça dans le monde réel ? Les signatures de webhooks. Quand GitHub ou Stripe envoie un webhook à votre serveur, ils incluent une signature HMAC-SHA256 dans les en-têtes. Votre serveur peut vérifier que le webhook provient bien de GitHub (et n'a pas été falsifié par un attaquant quelconque) en calculant le HMAC vous-même et en comparant.

Voici un exemple pratique de vérification d'une signature de webhook GitHub en Node.js :

javascript

Vous avez remarqué l'appel à timingSafeEqual ? C'est crucial. Une comparaison classique avec === retourne false dès qu'elle trouve le premier caractère qui ne correspond pas, ce qui signifie qu'un attaquant peut mesurer le temps de réponse et deviner la signature octet par octet. La comparaison sécurisée en temps prend toujours la même durée, peu importe où se trouve la différence.

Benchmarks de performance des fonctions de hachage

Écoutez, je comprends — la performance compte. Surtout si vous hachez des millions de fichiers dans un pipeline de build ou traitez un flux massif de données. Voici comment les principales fonctions de hachage se comparent en vitesse (benchmarks approximatifs sur du matériel x86_64 moderne) :

plaintext

Attendez, vous avez vu ça ? BLAKE3 est 10 fois plus rapide que SHA-256 tout en étant cryptographiquement sûr. Ce n'est pas une faute de frappe.

BLAKE3 est la dernière sensation du monde du hachage, et pour de bonnes raisons. Il est basé sur la famille BLAKE2 (qui avait déjà surpassé SHA-3 dans la compétition du NIST) mais reconçu pour exploiter le parallélisme SIMD et le multithreading. Il peut hacher des données pratiquement à la vitesse de memcpy.

Pourquoi devriez-vous vous en soucier ? Les outils de build s'en soucient. Énormément. Des outils comme Bazel, Buck et divers systèmes de stockage adressé par contenu passent un temps fou à hacher des fichiers. Passer de SHA-256 à BLAKE3 peut accélérer la vérification des dépendances d'un ordre de grandeur. L'écosystème Rust adopte BLAKE3 de manière agressive, et il apparaît dans de plus en plus d'endroits.

Cela dit, SHA-256 et SHA-512 restent le bon choix quand vous avez besoin d'une large compatibilité ou de conformité avec des standards comme FIPS. Tout ne supporte pas encore BLAKE3, et dans beaucoup de cas d'usage, la vitesse de hachage n'est de toute façon pas le goulot d'étranglement.

Blockchain et arbres de Merkle : Le hachage à grande échelle

OK, c'est là que ça devient vraiment passionnant. Vous savez comment Git peut vous dire exactement quel fichier a changé dans un immense dépôt ? Et comment Bitcoin peut vérifier une transaction sans télécharger toute la blockchain ? Le secret est une structure de données appelée arbre de Merkle (du nom de Ralph Merkle, qui l'a breveté en 1979).

Un arbre de Merkle est essentiellement un arbre de hashes. Voici comment ça marche — imaginez que vous avez quatre blocs de données :

plaintext

Chaque nœud feuille est le hash d'un bloc de données. Chaque nœud parent est le hash de ses deux enfants concaténés. Le hash racine (parfois appelé « Merkle root ») est un seul hash qui représente TOUTES les données de l'arbre.

Voici la partie vraiment élégante : si ne serait-ce qu'un bit de Data C change, Hash(C) change, ce qui signifie que Hash(CD) change, ce qui signifie que le Root Hash change. Vous pouvez détecter une falsification instantanément en vérifiant juste la racine.

Mais ça s'améliore encore. Disons que vous voulez prouver que Data C fait partie de l'arbre sans révéler Data A, B ou D. Vous n'avez qu'à fournir : Data C, Hash(D) et Hash(AB). Le vérificateur peut reconstruire le chemin jusqu'à la racine et vérifier qu'il correspond. C'est ce qu'on appelle une « preuve de Merkle », et c'est incroyablement efficace — pour un arbre avec un million de feuilles, la preuve ne fait qu'environ 20 hashes de long (log2 de 1 000 000).

Où est-ce utilisé en pratique ?

  • Git : Votre dépôt entier est un arbre de Merkle. Les commits pointent vers des arbres, les arbres pointent vers des blobs, et tout est identifié par son hash SHA-1. C'est pourquoi Git peut instantanément savoir si quelque chose a changé.
  • Bitcoin : Chaque bloc contient un Merkle root de toutes les transactions. Les clients légers (comme les portefeuilles mobiles) peuvent vérifier une transaction spécifique en utilisant une preuve de Merkle sans télécharger le bloc complet.
  • IPFS : Le Système de Fichiers InterPlanétaire découpe les fichiers en morceaux, construit un Merkle DAG (graphe acyclique dirigé) et utilise le hash racine comme identifiant de contenu (CID) du fichier.
  • Certificate Transparency : Les journaux de Certificate Transparency de Google utilisent des arbres de Merkle pour que n'importe qui puisse vérifier efficacement si un certificat a été (ou non) enregistré.

L'avenir : Les fonctions de hachage post-quantiques

Vous avez peut-être entendu dire que les ordinateurs quantiques vont casser toute notre cryptographie. Et oui, c'est en partie vrai — RSA, ECC et Diffie-Hellman sont tous condamnés une fois que les ordinateurs quantiques à grande échelle arriveront. L'algorithme de Shor peut factoriser de grands nombres et calculer des logarithmes discrets efficacement, ce dont dépendent ces systèmes.

Mais voici la nouvelle étonnamment bonne : les fonctions de hachage sont en fait assez sûres face aux ordinateurs quantiques. La principale menace quantique pour les fonctions de hachage est l'algorithme de Grover, qui peut parcourir un espace non structuré quadratiquement plus vite. En pratique, cela signifie que les bits de sécurité sont divisés par deux — SHA-256 passe de 2^256 à 2^128 de résistance contre les attaques quantiques.

2^128 reste absolument gigantesque. C'est à peu près le nombre d'atomes dans l'univers observable au carré. Personne ne forcera ça par force brute, ordinateur quantique ou pas.

Donc tandis que le NIST travaille activement sur les standards de cryptographie post-quantique (et en a finalisé plusieurs en 2024), l'urgence concerne principalement le chiffrement à clé publique et les signatures — pas les fonctions de hachage. Si vous utilisez SHA-256 aujourd'hui, vous pouvez dormir tranquille en sachant que les ordinateurs quantiques ne le rendront pas inutile.

Cela dit, si vous êtes vraiment paranoïaque (et en cryptographie, la paranoïa est une vertu), passer à SHA-512 ou SHA3-256 vous donne une marge de sécurité supplémentaire. Certains schémas de signature post-quantiques comme SPHINCS+ sont entièrement construits sur des fonctions de hachage, ce qui est un joli vote de confiance en leur résistance quantique.

Collisions de hash : Les attaques par anniversaire expliquées

Parlons de l'une des choses les plus contre-intuitives de toute l'informatique : l'attaque par anniversaire. Elle tire son nom du paradoxe des anniversaires, et c'est la raison pour laquelle les fonctions de hachage doivent être plus grandes que ce qu'on pourrait intuitivement penser.

Voici le paradoxe des anniversaires : dans une pièce de seulement 23 personnes, il y a 50 % de chances que deux d'entre elles partagent le même anniversaire. Pas un anniversaire spécifique — juste n'importe quelle paire correspondante. Avec 70 personnes, la probabilité monte à 99,9 %. La plupart des gens devineraient qu'il faut environ 183 personnes (la moitié de 365), mais le nombre réel est bien plus bas parce qu'on cherche N'IMPORTE QUELLE collision, pas une spécifique.

Exactement les mêmes mathématiques s'appliquent aux fonctions de hachage. Si une fonction de hachage produit N sorties possibles, vous n'avez pas besoin de calculer N hashes pour trouver une collision — vous n'avez besoin que d'environ la racine carrée de N.

Pour un hash de 256 bits comme SHA-256, il y a 2^256 sorties possibles. Trouver une collision nécessite environ 2^128 opérations (la racine carrée de 2^256). C'est toujours un nombre impossiblement grand — mais c'est la raison pour laquelle on ne peut pas simplement utiliser un hash de 64 bits et s'arrêter là.

plaintext

C'est exactement pour ça que MD5 (128 bits) s'est effondré. Sa résistance aux collisions n'était que de 2^64 au départ, et les faiblesses structurelles de l'algorithme l'ont encore réduite. Les chercheurs ont fini par trouver des collisions en quelques secondes sur un ordinateur portable ordinaire.

La conclusion pratique ? Utilisez toujours au moins une fonction de hachage de 256 bits pour tout ce qui touche à la sécurité. SHA-256, SHA3-256 ou BLAKE3 sont tous d'excellents choix. Et si quelqu'un suggère d'utiliser un hash de 64 ou 128 bits à des fins de sécurité, vous savez maintenant exactement pourquoi c'est une terrible idée.

Essayez vous-même

Curieux de voir le hash de vos données ? Utilisez notre Générateur de hash MD5, Générateur de hash SHA-256 ou Générateur de hash SHA-512. Collez du texte et voyez comment même de minuscules modifications produisent des hashes complètement différents — c'est la meilleure façon de développer une intuition sur le comportement de ces algorithmes.