NodeJS implementation for Python's pbkdf2_sha256.verify
Asked Answered
L

5

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.

Lite answered 31/7, 2018 at 13:0 Comment(0)
C
4

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, '.')
}
Covenantor answered 1/8, 2018 at 16:37 Comment(0)
B
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.

Blade answered 24/7, 2020 at 20:35 Comment(0)
H
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.

Heads answered 31/7, 2018 at 13:33 Comment(1)
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.Lite
A
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');
}
Agueweed answered 17/11, 2020 at 12:57 Comment(0)
Z
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

Zooplasty answered 9/6, 2021 at 5:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.