Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to store crypto pbkdf2 in mongoDB?
    text
    copied!<p>I'm using the following function to hash a user's password, following Express's example for authentication:</p> <pre><code>function hash(pwd, salt, fn) { // Bytesize var len = 128, // Iterations. ~300ms iterations = 12000; if (3 == arguments.length) { crypto.pbkdf2(pwd, salt, iterations, len, fn); } else { fn = salt; crypto.randomBytes(len, function(err, salt){ if (err) return fn(err); salt = salt.toString('base64'); crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){ if (err) return fn(err); fn(null, salt, hash); }); }); } } </code></pre> <p>The <code>salt</code>, as you can see, is returned as a string encoded in base64. The <code>hash</code>, however, is returned as a <code>SlowBuffer</code>. This same function is also used to compare hashes when trying to log a user in.</p> <p>My Mongoose schema for Users specifies that the <code>hash</code> should be of type <code>String</code>. This ends up storing the hash in a strange way, resulting in contents like this which wreaked havoc on my mongo host: </p> <p><img src="https://i.stack.imgur.com/8jqBJ.png" alt="screenshot of hash in mongodb"> </p> <p>My question is, is there a better/smarter way to store this <code>hash</code> in my database? I've tried encoding it with <code>.toString('hex')</code>, and I've also tried changing the <code>hash</code> type in the User schema to <code>buffer</code>, but both these approaches made all comparisons false when trying to log users in. Comparisons are made in my <code>authenticate</code> function, seen below:</p> <pre><code>function authenticate(name, pass, fn) { var findUser = function(username) { var deferred = Q.defer(), populateObj = [ // list of paths to populate objects normally goes here ]; User.findOne({ username: name }).populate(populateObj).exec(function (err, retrievedUser) { if (err || !retrievedUser) { console.log(err); deferred.reject('Cannot find user.'); } else { deferred.resolve(retrievedUser); } }); return deferred.promise; }; findUser(name).then(function(data) { // apply the same algorithm to the POSTed password, applying // the hash against the pass / salt, if there is a match we // found the user hash(pass, data.salt, function(err, hash){ if (err) return fn(err); if (hash == data.hash) return fn(null, data); return fn('Invalid password.'); }); }, function() { return fn('Failed to retrieve user.'); }); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload