21

I am looking to find bcrypt hash string using regex (in PowerGrep), in a database.

Tried this regex:

{?A-Za-z_0-9.{60}}?

But no match was found. Bcrypt hash is 60 characters length, and starts with "$2y$".

Example:

$2y$15$nK/B6u765645/lo0867h56546v/BnH5U5g45Aj67u67nMVtrhryt6
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Jim
  • 213
  • 2
  • 4

4 Answers4

27

Just as an addition to the answer above from @stribizhev. The bcrypt hashes you might encounter out there in the wild come in a few varieties, so you may have to modify the regex to catch all of them. The variations are as follows:

The "Algorithm Identifier" portion of the hash may include:

  • "2" - the first revision of BCrypt, which suffers from a minor security flaw and is generally not used anymore.

  • "2a" - some implementations suffered from a very rare security flaw.

  • "2y" - format specific to the crypt_blowfish BCrypt implementation, identical to "2a" in all but name.

  • "2b" - latest revision of the official BCrypt algorithm

^\$2[ayb]\$.{56}$

seems to work for me

see here for the breakdown of a bcrypt hash: Can someone explain how BCrypt verifies a hash?

Community
  • 1
  • 1
Calvin Alvin
  • 2,448
  • 2
  • 16
  • 15
  • 3
    I've updated your regex to be a bit more precise: `^\$2[ayb]\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}$`. This checks for the cost value after the version identifier and refines the character class for the salt and hash bits. Depending on your interpreter, you may not need to escape the `/` in the regex. For the cost value, this simply checks the format, not whether the value is valid (valid values are 4-31, inclusive). – Rand Aug 08 '16 at 13:53
  • Over time, the length could get longer than 60 if you are bcrypting using php's new password_hash function. For this reason, a regex of `^\$2[ayb]\$.+$` may be more appropriate. – Ben Grant Dec 29 '16 at 08:13
  • Rand, [ayb] should be optional to support the oldest version: `^\$2[ayb]?\$...` – ivant Dec 06 '18 at 09:13
14

Update:

Since beside the y value there might be a or b, you may use

^\$2[ayb]\$.{56}$

See the regex demo online. Details:

  • ^ - start of a string
  • \$ - a literal $ char (it should be escaped in a regex pattern to match a literal $ char, else, it will denote the end of string)
  • 2 - a 2 char
  • [ayb] - a character class matching any single char out of the specified set
  • \$ - a $ char
  • .{56} - any 56 chars other than line break chars (if not POSIX compliant regex engine is used, else, it will match any chars; to match any chars in common NFA engines, replace . with [\s\S] or use a corresponding DOTALL flag)
  • $ - end of string.

Original answer

Your regex - {?A-Za-z_0-9.{60}}? - contains ranges not inside a character class [...], but inside optional curly braces, and thus they present sequences of literal characters. See your regex demo to see what I mean.

You can use the following regex:

^\$2y\$.{56}$

See demo

The ^ matches the start of string, \$2y\$ matches $2y$ literally (as $ is a special character and needs escaping) and .{56} is the rest 56 characters.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
10

Use this:

^\$2[aby]?\$\d{1,2}\$[.\/A-Za-z0-9]{53}$

Explanation:

  • \$2[aby]?\$ - matches the algorithm used. Valid values are 2, 2a, 2y and 2b
  • \d{1,2}\$ - matches the cost, or how many rounds, which is an integer between 4 and 31 (inclusive)
  • [.\/A-Za-z0-9]{53} - matches the salt and the hash, with the salt making up the first 22 characters, and the hashed password making up the last 31
d4nyll
  • 11,811
  • 6
  • 54
  • 68
4

According to Wikipedia, bcrypt hashes follow the following format:

$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
\__/\/ \____________________/\_____________________________/
 Alg Cost      Salt                        Hash

Where valid values for each segment are:

  • Alg: 2, 2a, 2b, 2x or 2y
  • Cost: 4-31 (zero-padded to 2 digits)
  • Salt: ./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ x 22
  • Hash: ./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ x 31

Therefore, a comprehensive regex would look something like the following:

^[$]2[abxy]?[$](?:0[4-9]|[12][0-9]|3[01])[$][./0-9a-zA-Z]{53}$
Alix Axel
  • 151,645
  • 95
  • 393
  • 500