javascript - Comparing SHA256 made with PHP hash() and NodeJS crypto.createHash() - Stack Overflow

I'm working on making a real-time application for my website in NodeJS, allowing my users to log i

I'm working on making a real-time application for my website in NodeJS, allowing my users to log in with their accounts, etc.

However, I am having some issues with the logging in part.

When I register/login the users on the main site, I hashed their password using PHP's hash() function like so:

$passwordSalt = mcrypt_create_iv(100);
$hashed = hash("sha256", $password.$passwordSalt.$serverSalt);

and it works great on my site
However I need to be able to grab the user's salt from the database in NodeJS and be able to hash the user's inputted password, check it against the database's password, and make sure they match to log the user in.

I do this by doing something like this:

//Check if Username exists, then grab the password salt and password
//Hash the inputted password with the salt in the database for that user
//and the salt I used for $serverSalt in PHP when creating passwords
//check if hashed result in NodeJS is equal to the database password
function checkPass(dbPassword, password, dbSalt){
    var serverSalt = "mysupersecureserversalt";
    var hashed = crypto.createHash("sha256").update(password+dbSalt+serverSalt).digest('hex');
    if(hashed === dbPassword)
        return true;
    return false;
}

However, when I console.log() the hashed variable and the dbPassword variable, they're not equal - so it always return false/responds with incorrect password.

So, my question:
Is there any way I can accurately hash a sha256 string in NodeJS the same way I do in PHP?

PS: For now I am using Ajax/jQuery to login via PHP Script but I want to be able to pletely move from Apache/PHP hosting to the site just being hosted with NodeJS (SocketIO, Express, MySQL).

I just started working with NodeJS recently and I have made functionality on my Apache site to work with NodeJS, but I heard that hosting the whole site itself using NodeJS would be a lot better/more efficient.


Edit: So, I decided to make a quick test.js without using the database/socketio/express.

var crypto = require("crypto");
var serverSalt = "";
var passwordSalt = "­"; //The salt directly copied from database
var checkPassword = "password123"+passwordSalt+serverSalt; //All added together
var password = ""; //The hashed password from database
var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
console.log(password);
console.log(hashed); //This doesn't match the hash in the database
if(password == hashed){
        console.log("Logged in!");
} else {
        console.log("Error logging in!");
}

As for how I'm connecting to the database, I'm doing so:

  connection.query("SELECT password,passwordSalt FROM users WHERE username = "+connection.escape(data.username), function(err,res){
    if(err){console.log(err.stack);socket.emit("message", {msg:"There was an error logging you in!", mType:"error"});}else{
      if(res.length != 0){
        var dbSalt = res[0]['passwordSalt'];
        var serverSalt = ""; //My server salt
        var dbPassword = res[0]['password'];
        var checkPassword = data.password+dbSalt+serverSalt;
        console.log("CheckPass: "+checkPassword);
        var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
        console.log("Hashed: "+hashed);
        if(hashed === dbPassword){
          console.log("Worked!");
          socket.emit("message", {msg: "Logged in!", type:"success"});
        } else {
          console.log("Error logging in!");
          socket.emit("message", {msg: "Your password is incorrect!", type:"error"});
        }
      } else {
        socket.emit("message", {msg: "That user ("+data.username+") doesn't exist!", mType:"error"});
      }
    }
  });

MySQL version: 5.5.44-0+deb7u1 (Debian)
The column the password salt is stored in is type of text, and has a collation of utf8_unicode_ci


Note: When I change

var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
To:

var hashed = crypto.createHash("sha256").update(checkPassword, "utf8").digest('hex');

The hashes are different, however, the hashed variable doesn't match the database password still.

I'm working on making a real-time application for my website in NodeJS, allowing my users to log in with their accounts, etc.

However, I am having some issues with the logging in part.

When I register/login the users on the main site, I hashed their password using PHP's hash() function like so:

$passwordSalt = mcrypt_create_iv(100);
$hashed = hash("sha256", $password.$passwordSalt.$serverSalt);

and it works great on my site
However I need to be able to grab the user's salt from the database in NodeJS and be able to hash the user's inputted password, check it against the database's password, and make sure they match to log the user in.

I do this by doing something like this:

//Check if Username exists, then grab the password salt and password
//Hash the inputted password with the salt in the database for that user
//and the salt I used for $serverSalt in PHP when creating passwords
//check if hashed result in NodeJS is equal to the database password
function checkPass(dbPassword, password, dbSalt){
    var serverSalt = "mysupersecureserversalt";
    var hashed = crypto.createHash("sha256").update(password+dbSalt+serverSalt).digest('hex');
    if(hashed === dbPassword)
        return true;
    return false;
}

However, when I console.log() the hashed variable and the dbPassword variable, they're not equal - so it always return false/responds with incorrect password.

So, my question:
Is there any way I can accurately hash a sha256 string in NodeJS the same way I do in PHP?

PS: For now I am using Ajax/jQuery to login via PHP Script but I want to be able to pletely move from Apache/PHP hosting to the site just being hosted with NodeJS (SocketIO, Express, MySQL).

I just started working with NodeJS recently and I have made functionality on my Apache site to work with NodeJS, but I heard that hosting the whole site itself using NodeJS would be a lot better/more efficient.


Edit: So, I decided to make a quick test.js without using the database/socketio/express.

var crypto = require("crypto");
var serverSalt = "";
var passwordSalt = "­"; //The salt directly copied from database
var checkPassword = "password123"+passwordSalt+serverSalt; //All added together
var password = ""; //The hashed password from database
var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
console.log(password);
console.log(hashed); //This doesn't match the hash in the database
if(password == hashed){
        console.log("Logged in!");
} else {
        console.log("Error logging in!");
}

As for how I'm connecting to the database, I'm doing so:

  connection.query("SELECT password,passwordSalt FROM users WHERE username = "+connection.escape(data.username), function(err,res){
    if(err){console.log(err.stack);socket.emit("message", {msg:"There was an error logging you in!", mType:"error"});}else{
      if(res.length != 0){
        var dbSalt = res[0]['passwordSalt'];
        var serverSalt = ""; //My server salt
        var dbPassword = res[0]['password'];
        var checkPassword = data.password+dbSalt+serverSalt;
        console.log("CheckPass: "+checkPassword);
        var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
        console.log("Hashed: "+hashed);
        if(hashed === dbPassword){
          console.log("Worked!");
          socket.emit("message", {msg: "Logged in!", type:"success"});
        } else {
          console.log("Error logging in!");
          socket.emit("message", {msg: "Your password is incorrect!", type:"error"});
        }
      } else {
        socket.emit("message", {msg: "That user ("+data.username+") doesn't exist!", mType:"error"});
      }
    }
  });

MySQL version: 5.5.44-0+deb7u1 (Debian)
The column the password salt is stored in is type of text, and has a collation of utf8_unicode_ci


Note: When I change

var hashed = crypto.createHash("sha256").update(checkPassword).digest('hex');
To:

var hashed = crypto.createHash("sha256").update(checkPassword, "utf8").digest('hex');

The hashes are different, however, the hashed variable doesn't match the database password still.

Share edited Oct 6, 2015 at 4:11 Axiom asked Oct 6, 2015 at 0:09 AxiomAxiom 9021 gold badge10 silver badges24 bronze badges 4
  • 1 in my testing, as long as password == $password and dbSalt == $passwordSale and serverSalt == $serverSalt then php hash("sha256", ...) produces the exact same output as node crypto.createHash("sha256").update(...).digest('hex') - note createHash not hash – Jaromanda X Commented Oct 6, 2015 at 0:31
  • @JaromandaX odd.. Every time I test it, it looks similar but the hashes are different... Could it be the $passwordSalt that's messing it up? Maybe when it gets put into the mysql database? What I'm doing is checking if the username is in the database, if so, it grabs the password salt from the database (that was created when the password was created for that user), and hashed the inputted password with that, and pares the password with that of the user's – Axiom Commented Oct 6, 2015 at 0:43
  • I don't know what's messing it up, but php hash is identical to nodes crypto.createHash ... however, I have no idea what crypto.hash is, so that may be something you need to look at – Jaromanda X Commented Oct 6, 2015 at 0:44
  • Can you show the code used to retrieve the data ? What kind of DB field is the salt stored in ? And what is your MySQL version ? – spenibus Commented Oct 6, 2015 at 3:33
Add a ment  | 

1 Answer 1

Reset to default 5

TL;DR

2 possibilities:

  1. The ideal solution: change the database field for the salt from TEXT to BLOB.
  2. The promise: cast the TEXT to binary latin1 using:

    BINARY(CONVERT(passwordSalt USING latin1)) as passwordSalt
    

Then in both cases, use Buffer values everywhere:

var hashed = crypto.createHash("sha256").update(
    Buffer.concat([
        new Buffer(password),
        dbSalt, // already a buffer
        new Buffer(serverSalt)
    ])
).digest('hex');

It's tested and working.

The longer version

And of course the culprit is character encoding, what a surprise. Also a terrible choice on your part to store raw binary to a TEXT field.

Well, that was annoying to debug. So, I set up a MySQL table with a TEXT field and a BLOB field and stored the output of mcrypt_create_iv(100) in both. Then I made the same queries from both PHP and NodeJS.

  • PHP presents both values as identical.
  • JavaScript presents 2 different values.

In both cases, the BLOB was accurate and I even managed to get the proper hash under JavaScript by using Buffer values for all 3 ponents of the input.

But this did not explain why PHP and JavaScript were seeing 2 differents values for the TEXT field.

  • The TEXT value had a length of 143 octets.
  • The BLOB had a length of 100 octets.

Clearly the BLOB was correct and the TEXT wasn't, yet PHP didn't seem bothered by the difference.

If we look at the MySQL connection status under PHP:

$mysqli->get_charset();

Partial output:

[charset]   => latin1
[collation] => latin1_swedish_ci

Unsurprising really, it is notorious that PHP operates under ISO-8859-1 by default (or latin1 in MySQL), which is why both values where the same there.

For some reason, it seems that setting the charset in the MySQL module for NodeJS doesn't work, at least for me. The solution was to convert at the field level and preserve the data by casting to BINARY:

BINARY(CONVERT(passwordSalt USING latin1)) as passwordSalt

This returned exactly the same output as the BLOB.

But this is not enough yet. We have a mixture of strings and binary to feed to the hashing function, we need to consolidate that. We cast the password and the server salt to Buffer and concatenate:

var hashed = crypto.createHash("sha256").update(
    Buffer.concat([
        new Buffer(password),
        dbSalt, // already a buffer
        new Buffer(serverSalt)
    ])
).digest('hex');

This returns the same output as PHP.

While this works, the best solution is still to use BLOB in the database. In both cases, casting to Buffer is necessary.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745046295a4608117.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信