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);
using library bcrypt its easy to generate password hash.
npm install --save bcrypt
then include the library
const bcrypt = require( 'bcrypt' );
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
}
});
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
}
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.")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With