32

My php code generates a hash using password_hash which I store in a database. Below is the PHP code:

$hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => $cost));

I would like to verify / check the password against this hash in nodejs.

I saw lot of node modules (bcrypt, phpass, node-bcrypt), but all of them give me false. Below is sample hash generated in php and which I m trying to verify in nodejs.

var hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';

var bcrypt = require('bcrypt');

bcrypt.compare("secret", hash, function(err, res) {
    console.log(res);
});

(Here secret is real password)

My current workaround is to call a php script via node to verify (for anybody who needs a workaround)

var exec = require('child_process').exec;
var cmd = 'php verify.php password encryped_pasword';
exec(cmd, function (error, stdout, stderr) {
  // output is in stdout
  console.log(stdout);
 //If stdout has 1 it satisfies else false
});

This is a hack and not a good answer to this problem. Is there a way to verify the password in nodejs without using a workaround like this?

Andy Fleming
  • 7,655
  • 6
  • 33
  • 53
Sudesh
  • 1,129
  • 3
  • 14
  • 29

2 Answers2

65

Replace $2y$ in the hashed password with $2a$,then bcrypt.compare should give you correct result.

var hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';
var bcrypt = require('bcrypt');
hash = hash.replace(/^\$2y(.+)$/i, '$2a$1');
bcrypt.compare("secret", hash, function(err, res) {
    console.log(res);
});

on ES6:

import bcrypt from 'bcrypt';
let hash = '$2y$08$9TTThrthZhTOcoHELRjuN.3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2';
hash = hash.replace(/^\$2y(.+)$/i, '$2a$1');
bcrypt.compare('secret', hash, function(err, res) {
    console.log(res);
});
Idan Gozlan
  • 3,173
  • 3
  • 30
  • 47
Calvin Liu
  • 651
  • 5
  • 3
  • 4
    This helped me a lot thanks! Though would be interested to know why this is required if anyone knows? – iamjonesy Mar 09 '15 at 12:13
  • 1
    Commenting to get updates on this (if any since it has been more than a year!) – Sushruth Mar 09 '16 at 16:22
  • 1
    I wish this was Medium and I could give this a few more well deserved upvotes – Steven Kaspar Apr 05 '18 at 21:03
  • Thanks for the answer! – shilpa sree Sep 05 '18 at 08:31
  • 8
    `$2a$` or `$2y$` is only a prefix that indicates the version of the algorithm that's being used. In 2011 there was a major bug in the PHP implementation, and there was a initiative to change the original prefix `$2a$` to `$2x$` to indicate that the hash was done with the bugged algorithm and `$2y$` to indicate it was correct. No one but PHP took the recommendation. That's why node.js bcrypt doesn't recognize that prefix and PHP crypt_blowfish does. – Eduardo Palacio Jun 20 '19 at 03:23
32

I know this has been answered, but it seems from the comments that a little more detail is required.

Bcrypt hashes produced by the php password_hash() function are split as follows:

$2y$ 08$ 9TTThrthZhTOcoHELRjuN. 3mJd2iKYIeNlV/CYJUWWRnDfRRw6fD2

|     |     |                     |
|     |     Salt                  Hashed Password
|     |
|     Algorithm options (cost, in this case)
|
Algorithm type

It seems from other answers here on SO that while the PHP and Node versions of Bcrypt use different algorithms, the only difference in the hash output is the prefix. So all that is required is, as mentioned by @Sudesh, to swap the $2y$ for a $2a$ and Bob's your uncle.

Sources

http://php.net/manual/en/faq.passwords.php

$2y bcrypt hashes in Node.js

Comparing BCrypt hash between PHP and NodeJS

Community
  • 1
  • 1