Hello,

I've recently been working with a database containing bcrypt hashes generated 
by a 3rd-party which use the $2b$ prefix. This prefix was introduced in 2014 
and has since been recognised by a number of bcrypt implementations. 
[1][2][3][4]

At the moment, pgcrypto’s `crypt` doesn’t recognise this prefix. However, 
simply `replace`ing the prefix with $2a$ allows crypt to validate the hashes. 
This patch simply adds recognition for the prefix and treats the hash 
identically to the $2a$ hashes.

Is this a reasonable change to pgcrypto? I note that the last upstream change 
brought into crypt-blowfish.c was in 2011, predating this prefix. [5] Are there 
deeper concerns or other upstream changes that need to be addressed alongside 
this? Is there a better approach to this? 

At the moment, the $2x$ variant is supported but not mentioned in the docs, so 
I haven’t included any documentation updates.

Thanks,

Daniel


[1]: https://marc.info/?l=openbsd-misc&m=139320023202696
[2]: https://www.openwall.com/lists/announce/2014/08/31/1
[3]: 
https://github.com/kelektiv/node.bcrypt.js/pull/549/files#diff-c55280c5e4da52b0f86244d3b95c5ae0abf2fcd121a071dba1363540875b32bc
[4]: 
https://github.com/bcrypt-ruby/bcrypt-ruby/commit/d19ea481618420922b533a8b0ed049109404cb13
[5]: 
https://github.com/postgres/postgres/commit/ca59dfa6f727fe3bf3a01904ec30e87f7fa5a67e

diff --git a/contrib/pgcrypto/crypt-blowfish.c 
b/contrib/pgcrypto/crypt-blowfish.c
index a663852c..9012ca43 100644
--- a/contrib/pgcrypto/crypt-blowfish.c
+++ b/contrib/pgcrypto/crypt-blowfish.c
@@ -618,7 +618,7 @@ _crypt_blowfish_rn(const char *key, const char *setting,
 
        if (setting[0] != '$' ||
                setting[1] != '2' ||
-               (setting[2] != 'a' && setting[2] != 'x') ||
+               (setting[2] != 'a' && setting[2] != 'b' && setting[2] != 'x') ||
                setting[3] != '$' ||
                setting[4] < '0' || setting[4] > '3' ||
                setting[5] < '0' || setting[5] > '9' ||
diff --git a/contrib/pgcrypto/expected/crypt-blowfish.out 
b/contrib/pgcrypto/expected/crypt-blowfish.out
index d79b0c04..3d6b215c 100644
--- a/contrib/pgcrypto/expected/crypt-blowfish.out
+++ b/contrib/pgcrypto/expected/crypt-blowfish.out
@@ -13,6 +13,13 @@ SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
  $2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C
 (1 row)
 
+-- support $2b$ hashes
+SELECT crypt('password', 
'$2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW');
+                            crypt                             
+--------------------------------------------------------------
+ $2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW
+(1 row)
+
 -- error, salt too short:
 SELECT crypt('foox', '$2a$');
 ERROR:  invalid salt
diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c
index 0913ff2c..9272d409 100644
--- a/contrib/pgcrypto/px-crypt.c
+++ b/contrib/pgcrypto/px-crypt.c
@@ -78,6 +78,7 @@ struct px_crypt_algo
 static const struct px_crypt_algo
                        px_crypt_list[] = {
        {"$2a$", 4, run_crypt_bf},
+       {"$2b$", 4, run_crypt_bf},
        {"$2x$", 4, run_crypt_bf},
        {"$2$", 3, NULL},                       /* N/A */
        {"$1$", 3, run_crypt_md5},
diff --git a/contrib/pgcrypto/sql/crypt-blowfish.sql 
b/contrib/pgcrypto/sql/crypt-blowfish.sql
index 3b5a681c..0e96ee0c 100644
--- a/contrib/pgcrypto/sql/crypt-blowfish.sql
+++ b/contrib/pgcrypto/sql/crypt-blowfish.sql
@@ -6,6 +6,9 @@ SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
 
 SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
 
+-- support $2b$ hashes
+SELECT crypt('password', 
'$2b$06$cqhNY4qXkVeKliLWOxCFieDY6/J4SmCEojsXfHs7iF4X1r3tuNepW');
+
 -- error, salt too short:
 SELECT crypt('foox', '$2a$');
 

Reply via email to