Bcrypt
Générez un hachage bcrypt ou vérifiez un mot de passe, sans rien envoyer : choisissez le coût et la variante $2a$, $2b$ ou $2y$, et décomposez tout hachage.
Rien de ce que vous saisissez ici ne quitte ce navigateur. Le calcul tourne dans un Web Worker de cet onglet : ouvrez votre propre panneau réseau et regardez, aucune requête ne sort pendant ce temps.
Générer un hachage
Un mot de passe, un coût et une variante. Le sel est tiré neuf de ce navigateur à chaque exécution, si bien que le même mot de passe donne un hachage différent à chaque fois : c’est bcrypt qui fonctionne, pas un défaut.
Vérifier un mot de passe contre un hachage
Un hachage collé est décomposé aussitôt, sans mot de passe et sans attente. Ajoutez le mot de passe pour savoir s’il correspond. Un hachage ne s’inverse pas, ici pas plus qu’ailleurs.
Ce qu’un hachage bcrypt contient réellement
Un hachage bcrypt est une seule chaîne de soixante caractères, et chacune de ses parties est à découvert. Rien n’y est secret sauf le mot de passe qui l’a produite, et celui-là n’y est pas du tout. La décomposer ne demande ni clé, ni mot de passe, ni le moindre calcul : cette page le fait à l’instant où vous en collez une.
- La variante, le champ par lequel la chaîne commence : $2b$, $2a$ ou $2y$. Elle dit selon les règles de qui le hachage a été produit.
- Le coût, écrit sur exactement deux chiffres : de 04 à 31. C’est un exposant, si bien qu’un coût de 12 veut dire 2^12 — 4 096 — tours d’étirement de clé, et que le coût 13 représente deux fois le travail du coût 12 et non un treizième de plus.
- Le sel, vingt-deux caractères : seize octets aléatoires, conservés en clair à côté de la réponse qu’ils ont salée.
- Le condensé, les trente et un derniers caractères : vingt-trois octets de sortie. C’est la seule partie qui dépende du mot de passe, et ce n’est pas le hachage — le hachage, c’est la chaîne entière.
L’alphabet d’où ces caractères sont tirés est celui de bcrypt lui-même, et ce n’est pas le Base64 standard : il va ./A-Za-z0-9, si bien qu’un point et une barre oblique l’ouvrent là où Base64 met le plus et la barre à la fin. Le passer dans un décodeur Base64 ordinaire rend des octets faux plutôt qu’une erreur, ce qui est une manière classique de perdre un après-midi.
La limite de soixante-douze octets se compte en octets, et ce n’est pas un détail
bcrypt lit au plus soixante-douze octets d’un mot de passe et ignore tout ce qui vient après. Pas soixante-douze caractères — soixante-douze octets d’UTF-8, si bien que le nombre de caractères que cela représente dépend de ce que coûtent les lettres de la langue : les vingt-six lettres latines sans signe coûtent un octet chacune, et toute autre lettre coûte davantage. En français l’écart est petit et réel à la fois : chaque lettre qui porte un accent, un tréma ou une cédille coûte deux octets, si bien qu’un mot de passe portant quelques accents atteint la limite un peu avant soixante-douze caractères. Un mot de passe fait uniquement de lettres accentuées l’atteindrait à trente-six.
- L’ASCII coûte un octet par caractère : celui qui parle anglais rencontre la limite à soixante-douze caractères et n’y arrive presque jamais.
- L’hébreu, l’arabe, le russe et le grec coûtent deux octets par lettre, si bien que la limite arrive à trente-six caractères.
- Le japonais, le coréen et le chinois coûtent trois, si bien qu’elle arrive à vingt-quatre.
- La plupart des émojis coûtent quatre, et beaucoup de ceux que les gens tapent vraiment sont plusieurs points de code assemblés : une poignée suffit déjà à épuiser tout le budget.
Le compteur d’octets sous le champ du mot de passe est là pour que ce soit une chose que vous voyez venir plutôt que découvrir après coup. Et la coupe tombe à l’octet et non au caractère, exactement comme le fait toute implémentation de référence — un caractère multi-octets assis sur la frontière perd donc une partie de lui-même et garde le reste. C’est le comportement compatible et non un défaut, et cette page le dit quand cela arrive.
Et voici la partie qui explique tout le reste : la troncature est invisible dans la réponse. L’expansion de la clé mêle exactement soixante-douze octets de clé à son état et n’en reboucle jamais un plus long, si bien que hacher un mot de passe de cent octets et hacher ses soixante-douze premiers octets donnent le même condensé. Il n’y a rien qu’une implémentation puisse détecter et rien qu’elle puisse signaler, et c’est pourquoi aucune bibliothèque ne lève d’erreur et pourquoi deux longs mots de passe différents qui s’accordent sur leurs soixante-douze premiers octets correspondent tous les deux au même hachage stocké. Cette page ne peut pas non plus refuser un long mot de passe — si vous le vérifiez contre un hachage qu’un vrai système a produit en tronquant, il vous faut la réponse — alors elle donne la réponse et vous dit ce qui a été coupé.
La variante change le préfixe et non le condensé
La variante ressemble à un numéro de version et n’en est pas un. Les trois que cet outil écrit ne sont pas ordonnées, aucune ne remplace les autres, et choisir entre elles est une décision de compatibilité et non de sécurité.
- $2b$ est celle sur laquelle OpenBSD s’est arrêté et celle qu’émettent aujourd’hui Python, Node et Go. C’est la valeur par défaut ici et la bonne réponse quand rien n’en impose une autre.
- $2a$ est la plus ancienne, et certains déploiements Java et Spring Security de longue date s’attendent encore à la voir.
- $2y$ est celle qu’écrit le password_hash de PHP, et donc Laravel, si bien qu’un hachage collé dans ce monde-là la réclame en général.
Ce qui sépare les trois, c’est la façon dont elles traitent une clé de plus de 255 octets, et bcrypt a déjà cessé de lire à soixante-douze — aucun mot de passe que vous pouvez taper ici n’atteint donc cette différence. Pour tout ce que cet outil recevra jamais, les trois produisent les mêmes vingt-trois octets et ne diffèrent que par les quatre caractères de tête. Changez la variante et le condensé ne bouge pas.
Il en existe deux autres, et cet outil les nomme au lieu de les calculer. $2x$ n’est pas un correctif : Openwall l’a frappée pour reproduire à dessein un bogue d’extension de signe, afin que les hachages faits par le code cassé restent vérifiables, et l’implémenter ici reviendrait à installer un défaut connu à l’intérieur de l’outil. $2$ est la variante d’origine, d’avant l’ajout de l’octet nul final à la clé. Plus rien d’actuel n’émet l’une ou l’autre ; si vous en tenez une, elle sort d’un système assez vieux pour que la variante soit le moindre de vos soucis.
Le coût, et ce qu’il coûte sur votre propre machine
Le coût est le facteur de travail, de 4 à 31, et c’est un exposant : chaque cran double le temps. C’est tout l’intérêt de bcrypt. Un hachage de mot de passe doit être lent, parce qu’un attaquant qui tient une table volée paie le même prix à chaque essai, et que doubler le coût divise par deux le nombre d’essais par seconde qu’il obtient pour son argent.
Ce qu’un coût donné prend réellement est un fait sur la machine qui l’exécute, pas un nombre qui s’écrit à l’avance : un téléphone et un serveur sont à deux ordres de grandeur l’un de l’autre. Cette page mesure donc au lieu de citer : elle lance un hachage court sur votre propre appareil au chargement et extrapole de là, ce qui explique que l’estimation à côté du réglage du coût soit vide un instant puis apparaisse. Au-delà de quelques secondes, elle demande avant de commencer, pour qu’un chiffre mal tapé ne se lise pas comme une page figée.
Pour choisir un nombre : 12 est ce qu’émettent par défaut Laravel et le paquet bcrypt de Python, et c’est aujourd’hui un plancher de production raisonnable. Les coûts plus bas sont pour les fixtures de test, où une suite qui sème cinquante utilisateurs ne devrait pas passer une seconde par utilisateur. Les coûts au-dessus de 15 environ méritent d’être mesurés contre votre vrai trafic de connexion avant d’être livrés, puisque chaque connexion en paie le prix elle aussi.
# Apache : écrire une ligne htpasswd au coût 12
htpasswd -nbBC 12 alice "correct horse battery staple"
# PHP et Laravel : password_hash émet $2y$
php -r 'echo password_hash("correct horse battery staple", PASSWORD_BCRYPT);'
# Python : le paquet bcrypt émet $2b$, et gensalt prend le coût
python -c "import bcrypt; print(bcrypt.hashpw(b'correct horse battery staple', bcrypt.gensalt(12)))"Le sel, et quand un hachage fait ici n’est pas à stocker
Le sel, ce sont seize octets aléatoires tirés neufs pour chaque hachage, et il est conservé en clair à l’intérieur de la chaîne. Ce n’est pas un secret et cela n’a jamais été prévu pour en être un : son travail est de faire que deux mots de passe identiques produisent deux hachages sans rapport, pour qu’une table volée ne puisse pas être attaquée avec un seul dictionnaire précalculé.
C’est aussi pourquoi le même mot de passe vous donne ici un hachage différent à chaque appui sur le bouton. Ce n’est pas un défaut et l’ancienne réponse n’est pas périmée : un sel neuf, c’est bcrypt qui fonctionne. N’importe lequel de ces hachages correspond au mot de passe, parce que le sel voyage à l’intérieur de la chaîne que l’on vérifie.
Le champ avancé du sel existe pour une seule tâche : reproduire exactement le hachage de quelqu’un d’autre, afin de pouvoir mettre deux implémentations face à face. Collez-y un hachage entier et le coût et la variante le suivent automatiquement, si bien que le bon mot de passe reproduit l’entrée caractère pour caractère. Tout ce que vous produisez ainsi sert à comparer et non à stocker : un sel employé deux fois est un sel qui a cessé de faire son travail.
Un hachage bcrypt ne s’inverse pas
On arrive sur des pages comme celle-ci en cherchant un moyen de déchiffrer un hachage bcrypt. Il n’y en a pas, et la raison n’est pas que ce soit difficile : le mot de passe n’est pas dans la chaîne. Soixante caractères portent une variante, un coût, seize octets aléatoires et vingt-trois octets de sortie, et aucun arrangement de tout cela ne contient un mot de passe d’une longueur quelconque. Rien n’a été chiffré, il n’y a donc rien à déchiffrer.
Ce qu’un site peut faire — et ce que font ceux qui annoncent du déchiffrement — c’est deviner. On prend une liste de mots de passe courants, on hache chacun contre votre sel et à votre coût, et on regarde si l’un d’eux correspond. bcrypt est conçu pour rendre exactement cela coûteux, ce à quoi sert le coût, et cet outil ne le propose sous aucune forme.
La version honnête de cette question en est généralement une autre, et celle-là a une réponse : qu’y a-t-il dans cette chaîne, et ce mot de passe précis la produit-il ? Les deux sont sur cette page. Collez le hachage pour voir tout ce qu’il porte, et ajoutez un mot de passe pour obtenir un oui ou un non.
Questions fréquentes
- Mon mot de passe est-il envoyé à un serveur ?
- Non. Tout se passe dans cet onglet du navigateur : le hachage tourne dans un Web Worker sur votre propre machine, le mot de passe n’entre jamais dans l’adresse, et rien n’est écrit dans le stockage du navigateur. Ouvrez votre panneau réseau, tapez un mot de passe et appuyez sur le bouton : aucune requête ne sort. C’est la différence entre cette page et les deux sites qui la devancent sur la même question.
- Un hachage bcrypt peut-il être déchiffré pour retrouver le mot de passe ?
- Non, et pas parce que ce serait difficile. Le mot de passe n’est pas dans la chaîne : ce qui s’y trouve, c’est une variante, un coût, un sel et vingt-trois octets de sortie, et rien de tout cela ne contient l’entrée. Quiconque propose d’en déchiffrer un devine des mots de passe courants contre votre sel, ce que bcrypt est précisément conçu pour rendre lent.
- Pourquoi le même mot de passe donne-t-il un hachage différent à chaque fois ?
- Parce qu’un nouveau sel aléatoire est tiré à chaque exécution, et que le sel fait partie de la chaîne. Chacun de ces hachages correspond au même mot de passe — le vérificateur lit le sel dans le hachage que vous collez, il n’a donc pas besoin de savoir quelle exécution l’a produit.
- Mon mot de passe a été coupé à soixante-douze octets. Pourquoi n’y a-t-il pas eu d’erreur ?
- Parce qu’il n’y a rien à détecter. bcrypt mêle exactement soixante-douze octets de clé à son état et ne lit jamais plus loin : un long mot de passe et ses soixante-douze premiers octets donnent donc le même condensé, et la troncature ne laisse aucune trace qu’une bibliothèque pourrait remarquer. Cette page vous dit que cela s’est produit, ce qui est le maximum qu’une implémentation puisse honnêtement faire.
- Pourquoi mon mot de passe a-t-il atteint la limite à trente-six caractères ?
- Parce que la limite est de soixante-douze octets et non de soixante-douze caractères, et qu’une lettre hébraïque, arabe, russe ou grecque coûte deux octets en UTF-8. Les caractères japonais, coréens et chinois en coûtent trois, si bien que la limite y arrive à vingt-quatre caractères, et la plupart des émojis en coûtent quatre. En français, un accent, un tréma ou une cédille coûtent eux aussi deux octets : un mot de passe fait uniquement d’accents est coupé à trente-six. Le compteur sous le champ affiche le nombre d’octets à mesure que vous tapez.
- Quelle variante choisir ?
- Celle qu’attend le système où vous la collez : $2y$ pour PHP et Laravel, $2a$ pour un vieux Spring Security, $2b$ partout ailleurs. C’est une décision de compatibilité et non de sécurité — à n’importe quelle longueur que l’on puisse donner à cet outil, les trois produisent des condensés identiques et ne diffèrent que par ces quatre caractères de tête.
- Quel coût utiliser ?
- 12 est la valeur par défaut courante et un plancher de production raisonnable. Prenez un coût bas pour les fixtures de test, afin que votre suite ne paie pas cinquante fois l’étirement de clé, et mesurez d’abord tout ce qui dépasse 15 contre votre vrai trafic de connexion, parce que chaque connexion réussie paie le même prix qu’un attaquant.
- Un hachage fait ici peut-il aller sans risque dans une vraie table d’utilisateurs ?
- Pour semer une base, écrire une fixture ou ajouter une ligne htpasswd, oui : le sel vient de la source d’aléa cryptographique de votre navigateur. Mais ceci est une page de brouillon et non un service d’identifiants : si vous saisissez vous-même le sel, le résultat cesse d’être sûr à stocker — la page le dit sur le moment — et un mot de passe qui mérite d’être protégé se frappe mieux là où il va vivre.
- Pourquoi mon hachage commence-t-il par $2y$ alors que le code qui l’a fait dit bcrypt ?
- Parce que le password_hash de PHP écrit $2y$, et que Laravel est bâti dessus. C’est le même algorithme que $2b$ ; la variante enregistre quelle implémentation a écrit la chaîne. Un vérificateur qui la refuse refuse la variante, il n’échoue pas à faire correspondre le mot de passe.
- J’ai collé un hachage et il dit que le sel est écrit autrement. Est-il cassé ?
- Non. Vingt-deux caractères peuvent encoder plus de bits que seize octets n’en demandent : quatre bits de la fin sont donc abandonnés, et certains sels ont plus d’une écriture qui se décode vers les mêmes octets. De vrais systèmes en ont émis, alors cette page lit un tel hachage plutôt que de le refuser, et vous indique l’écriture canonique.
Outils connexes
- Décodeur / vérificateur de JWT
Décode et vérifie les JSON Web Tokens — signature et claims.
- Générateur de hachage
MD5, SHA-1, SHA-256, SHA-384 et SHA-512 d’un coup.
- Décodeur de certificats et de PEM
Lisez un certificat X.509 ou une CSR sans OpenSSL.
- Générateur HMAC
Signez un message avec une clé, ou vérifiez la signature d’un webhook.