Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Password Hashing in Node.js

Tags:

node.js

This is my current code for password hashing and saving to the database:

var config = {
  hashBytes: 64,
  saltBytes: 64,
  iterations: 8000
};

crypto.randomBytes(config.saltBytes, function(err, salt) {

  crypto.pbkdf2(password, salt, config.iterations, config.hashBytes,
      function(err, hash) {

          var combined = new Buffer(hash.length + salt.length + 8);

          combined.writeUInt32BE(salt.length, 0, true);
          combined.writeUInt32BE(config.iterations, 4, true);
          salt.copy(combined, 8);
          hash.copy(combined, salt.length + 8);

          callback(combined);
      });
  });

The goal of the code was to save salt together with the hash to one field in database. Is this acceptable way to store a password/salt in the same field in the database? I've found this algorithm long time ago and now so I'm not sure do I understand this well.

As I understand, first we create a buffer which has enough space to store hash, salt, number of iterations and salt length (not sure why are we adding 8 here):

var combined = new Buffer(hash.length + salt.length + 8); 

Then we save salt length byte to position 0:

combined.writeUInt32BE(salt.length, 0, true);

We save iterations position 4 (why 4?):

combined.writeUInt32BE(config.iterations, 4, true);

We save salt to position 8:

salt.copy(combined, 8);

We save hash to position which is the length of salt plus the size where we saved iterations and salt length:

hash.copy(combined, salt.length + 8);
like image 278
user3339562 Avatar asked Dec 08 '25 07:12

user3339562


2 Answers

using library bcrypt its easy to generate password hash.

install & Include

npm install --save bcrypt

then include the library

const bcrypt = require( 'bcrypt' );

Generate & Verify Hash

to generate hash in Asynchronous way use the following method.

bcrypt.hash( 'passwordToHash', 10, function( err, hash ) {
  // Store hash in database
});

10 is the number of rounds to use when generating a salt. to verify password

bcrypt.compare( 'passwordToCompare', hash, function( err, res ) {
  if( res ) {
   // Password matched
  } else {
   // Password didn't match
  } 
});

Generate & Verify Hash

to generate and verify hash in synchronous way use the following method.

let hash = bcrypt.hashSync( 'passwordToHash', 10 );

10 is the number of rounds to use when generating a salt. To verify hash

if( bcrypt.compareSync( 'passwordToCompare', hash ) ) {
   // Password matched
} else {
   // Password didn't match
}
like image 134
Aamer Shahzad Avatar answered Dec 09 '25 20:12

Aamer Shahzad


This code seems to be making the now-dangerous assumption that "an integer is 4 bytes long, therefore two integers are 8 bytes."

In today's 64-bit world, that assumption would no longer be true. And, in any case, we don't need this level of complexity and byte-twiddling!

A far better (and, far simpler) strategy ... (source-code example not shown) ... is to simply store all three values as strings, separated by a known character. For instance, 12:34:5678 being used to store a salt-length of 12, iterations 34, hash-value 5678. The code that stores the value simply concatenates the three strings and stores them in a VARCHAR field of sufficient size. And, in like manner, the code that retrieves and checks the value first "splits" the string into its three constituent parts (e.g. using a regex ...), converts the first two strings to integers, and proceeds to evaluate.

This is preferable for a great many reasons, not the least of which is that a human being, querying the database, can plainly see the three parts. (So, if there's a bug in the code somewhere, s/he can see the consequences of the bug "at a glance.")

like image 37
Mike Robinson Avatar answered Dec 09 '25 19:12

Mike Robinson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!