Search code examples
javascriptnode.jsauthenticationencryptionpbkdf2

binding.PBKDF2 error when hashing passwords Node.JS


I am trying to hash my passwords in the user model with crypto.PBKDF2 but my validatePassword method is failing with the following exception

return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);

This is the full error

crypto.js:562
return binding.PBKDF2(password, salt, iterations, keylen, digest, callback);
               ^
TypeError: Not a buffer
    at TypeError (native)
    at pbkdf2 (crypto.js:562:20)
    at Object.exports.pbkdf2Sync (crypto.js:553:10)
    at new <anonymous> (c:\Users\Joseph\news-trends\models\Users.js:25:23)
    at Object.<anonymous> (c:\Users\Joseph\news-trends\models\Users.js:24:39)
    at Module._compile (module.js:398:26)
    at Object.Module._extensions..js (module.js:405:10)
    at Module.load (module.js:344:32)
    at Function.Module._load (module.js:301:12)
    at Module.require (module.js:354:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (c:\Users\Joseph\news-trends\app.js:17:1)
    at Module._compile (module.js:398:26)
    at Object.Module._extensions..js (module.js:405:10)
    at Module.load (module.js:344:32)
    at Function.Module._load (module.js:301:12)

These are the relevant methods

UserSchema.methods.setPassword = function(password){
    var self = this;

    crypto.randomBytes(16, function(err, salt){
        if(err){ throw err; }
        self.salt = salt.toString('hex');
    });

    crypto.pbkdf2(password, this.salt, 1000, 64, function(err, hash){
        if(err){ throw err;}
        self.hash = hash.toString('hex');
    });
};
UserSchema.methods.validatePassword = new function(password){
    var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
    return this.hash = hash;
};

Here is a link to the full code: Repo


Solution

  • Your code is somewhat confusing, it sets a variable to an asynchronous function, and somehow tries to use that inside the function?

    crypto methods have a callback where the generated key is the second argument, and this is how you'd generally use them

    UserSchema.methods.setPassword = function(password){
    
        var self = this;
    
        crypto.randomBytes(16, function(err, salt){
            if(err){ throw err; }
            self.salt = salt.toString('hex');
        });
    
        crypto.pbkdf2(password, this.salt, 1000, 64, function(err, hash){
            if(err){ throw err;}
            self.hash = hash.toString('hex');
        });
    }
    
    UserSchema.methods.validatePassword = function(password){
        var hash = crypto.pbkdf2Sync(password, this.salt, 1000, 64).toString('hex');
        return this.hash === hash;
    };
    

    Note that your setPassword and validatePassword methods only works for one instance, which is probably fine for testing, but if you want more than one user, you probably need a database to hold those values, and not just assign them to this.

    The error you're getting is because you're trying to pass the returned result from the asynchronous functions to new Buffer, and not the generated keys