6

I have to translate this Python code to NodeJS:

from passlib.hash import pbkdf2_sha256
pbkdf2_sha256.verify('12345678', '$pbkdf2-sha256$2000$8R7jHOOcs7YWImRM6V1LqQ$CIdNv8YlLlCZfeFJihZs7eQxBsauvVfV05v07Ca2Yzg')
>> True

The code above is the entire code, i.e. there is no othe parameters/settings (just run pip install passlib before you run it to install the passlib package).

I am looking for the correct implementation of validatePassword function in Node that will pass this positive implementation test:

validatePassword('12345678', '$pbkdf2-sha256$2000$8R7jHOOcs7YWImRM6V1LqQ$CIdNv8YlLlCZfeFJihZs7eQxBsauvVfV05v07Ca2Yzg')
>> true

Here is the documentation of the passlib.hash.pbkdf2_sha256 with its default parameters' values.

I tried to follow the answers from here with the data from the Python code above, but that solutions didn't pass the test.

I would appreciate some help with this implementation (preferably using built-in NodeJS crypto package).

Thank you in advance.

5 Answers 5

3

This would work:

const crypto = require('crypto')
function validatePassword(secret, format) {
    let parts = format.split('$')
    return parts[4] == crypto.pbkdf2Sync(secret, Buffer.from(parts[3].replace(/\./g, '+') + '='.repeat(parts[3].length % 3), 'base64'),
        +parts[2], 32, parts[1].split('-')[1]).toString('base64').replace(/=/g, '').replace(/\+/g, '.')
}
Sign up to request clarification or add additional context in comments.

1 Comment

good god I'm adding this to my code wall of shame
2

I was not able to get this working with the other answers here, but they did lead me in the right direction.

Here's where I landed:

// eslint-2017
import crypto from 'crypto';
const encode = (password, { algorithm, salt, iterations }) => {
    const hash = crypto.pbkdf2Sync(password, salt, iterations, 32, 'sha256');
    return `${algorithm}$${iterations}$${salt}$${hash.toString('base64')}`;
};
const decode = (encoded) => {
    const [algorithm, iterations, salt, hash] = encoded.split('$');
    return {
        algorithm,
        hash,
        iterations: parseInt(iterations, 10),
        salt,
    };
};
const verify = (password, encoded) => {
    const decoded = decode(encoded);
    const encodedPassword = encode(password, decoded);
    return encoded === encodedPassword;
};
// <algorithm>$<iterations>$<salt>$<hash>
const encoded = 'pbkdf2_sha256$120000$bOqAASYKo3vj$BEBZfntlMJJDpgkAb81LGgdzuO35iqpig0CfJPU4TbU=';
const password = '12345678';
console.info(verify(password, encoded));

I know this is an old post, but it's one of the top results on Google, so figured I'd help someone out that comes across this in 2020.

Comments

0

You can use the crypto.pbkdf2 native node.js api

const crypto = require('crypto');
crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha256', (err, derivedKey) => {
  if (err) throw err;
  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
});

It is having the following api:

  • password <string>
  • salt <string>
  • iterations <number>
  • keylen <number>
  • digest <string>
  • callback <Function>
    • err <Error>
    • derivedKey <Buffer>

So you will need to play with the input variables to get the expected result as in python.

An alternative approach

I played with input variables, with not much success, and the simplest idea that I got is to make python scripts that validate the passwords and invoking it with child_process.spawn in node.js.

1 Comment

I am aware of crypto package (I even mentioned it in my question). Did you succeed to create a function validatePassword that will return true for validatePassword('12345678', '$pbkdf2-sha256$2000$8R7jHOOcs7YWImRM6V1LqQ$CIdNv8YlLlCZfeFJihZs7eQxBsauvVfV05v07Ca2Yzg') just like Python code does? I couldn't, that's why I asked this question.
0

This worked for me based on node-django-hasher(didn't use it because depends on node-gyp)

function validatePassword(plain, hashed) {
  const parts = hashed.split('$');
  const salt = parts[2];
  const iterations = parseInt(parts[1]);
  const keylen = 32;
  const digest = parts[0].split('_')[1];
  const value = parts[3];
  const derivedKey = crypto.pbkdf2Sync(plain, salt, iterations, keylen, digest);
  return value === Buffer.from(derivedKey, 'binary').toString('base64');
}

Comments

0

Finally solved it. Because passlib does some transformations on the base64 encoded strings none of the mentioned solutions worked for me. I ended up writing my own node-module wich is tested with passlib 1.7.4 hashes. Thanks @kayluhb for pushing me in the right direction!

Feel free to use it: node-passlib

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.