Regex bcrypt hash
A bcrypt hash is 60 characters: '$2b$' (version), a two-digit cost, '$', then 53 characters of the './A-Za-z0-9' alphabet (22 salt and 31 digest). OpenBSD's crypt(3) manual page gives the example '$2b$12$FPWWO2RJ3CK4FINTw0Hi8OiPKJcX653gzSS.jqltHFMxyDmmQ0Hqq'. The attempts I read disagree: Spring Security leaves the end unanchored (a 54th character passes) and accepts any two-digit cost, Name-That-Hash does the same, hashID rejects the '$2b$' version that appeared after it. Here's a pattern bounding the cost to 04-31, compared against those attempts.
/^\$2[abxy]\$(?:0[4-9]|[12][0-9]|3[01])\$[./A-Za-z0-9]{53}$/passes 24/24 cases
Comparison of existing patterns
| Source | pattern | Score on the corpus | ReDoS |
|---|---|---|---|
| Spring Security BCryptPasswordEncoder — pas d'ancre de fin (un 54e caractère passe), coût sur deux chiffres quelconque (00, 99), version « $2$ » sans lettre acceptée | ^\$2(a|y|b)?\$(\d\d)\$[./0-9A-Za-z]{53} | 16 / 24 | safe |
| Name-That-Hash — insensible à la casse (« $2A$ » passe), coût sur deux chiffres quelconque (00, 99) | ^(\$2[abxy]?|\$2)\$[0-9]{2}\$[a-z0-9\/.]{53}$ | 18 / 24 | safe |
| hashID — antérieur à « $2b$ » : refuse cette version, insensible à la casse, coût quelconque | ^(\$2[axy]|\$2)\$[0-9]{2}\$[a-z0-9\/.]{53}$ | 16 / 24 | safe |
Implementation
const re = new RegExp("^\\$2[abxy]\\$(?:0[4-9]|[12][0-9]|3[01])\\$[./A-Za-z0-9]{53}$", "");
re.test(input);Limits
- Valide seulement la FORME : 60 caractères, version, coût 04-31, alphabet. Rien ne prouve qu'une chaîne soit un vrai hachage bcrypt ni qu'elle corresponde à un mot de passe ; la comparaison se fait avec la fonction de la bibliothèque (compare), jamais en réimplémentant le calcul.
- La borne 04-31 du coût vient des implémentations, pas de la page de manuel OpenBSD ; la version historique « $2$ » (sans lettre) est refusée. Les variantes $2a$/$2x$/$2y$ sont celles de crypt_blowfish ; elles ne sont pas toutes équivalentes (voir la documentation de crypt_blowfish).
- Les hachages d'autres schémas (Argon2, scrypt, MD5-crypt, SHA-crypt) sont refusés : le préfixe doit être $2a$, $2b$, $2x$ ou $2y$. Aucun mot de passe réel dans les exemples.