Python 的 pbkdf2_sha256.verify 的 NodeJS 实现

NodeJS implementation for Python's pbkdf2_sha256.verify

我必须将此 Python 代码翻译成 NodeJS:

from passlib.hash import pbkdf2_sha256
pbkdf2_sha256.verify('12345678', '$pbkdf2-sha25600R7jHOOcs7YWImRM6V1LqQ$CIdNv8YlLlCZfeFJihZs7eQxBsauvVfV05v07Ca2Yzg')
>> True

上面的代码是完整的代码,即没有其他 parameters/settings(只是 运行 pip install passlib 在你 运行 安装 passlib 包裹)。

我正在寻找 Node 中 validatePassword 函数的正确实现,它将通过这个积极的实现测试:

validatePassword('12345678', '$pbkdf2-sha25600R7jHOOcs7YWImRM6V1LqQ$CIdNv8YlLlCZfeFJihZs7eQxBsauvVfV05v07Ca2Yzg')
>> true

这是 passlib.hash 的 documentation。pbkdf2_sha256 及其默认参数值。

我尝试使用上面 Python 代码中的数据来遵循 here 的答案,但是这些解决方案没有通过测试。

我希望能为这个实现提供一些帮助(最好使用内置的 NodeJS crypto 包)。

提前致谢。

可以使用crypto.pbkdf2原生node.jsapi

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

它具有以下 api:

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

所以您需要使用输入变量来获得预期的结果,如 python。

另一种方法

我玩过输入变量,但收效甚微,我得到的最简单的想法是制作 python 脚本来验证密码并在 [=51= 中使用 child_process.spawn 调用它].

这可行:

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, '.')
}

我无法将此与此处的其他答案一起使用,但它们确实引导我朝着正确的方向前进。

这是我着陆的地方:

// 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_sha2560000$bOqAASYKo3vj$BEBZfntlMJJDpgkAb81LGgdzuO35iqpig0CfJPU4TbU=';
const password = '12345678';
console.info(verify(password, encoded));

我知道这是一个旧 post,但它是 Google 上的最佳结果之一,所以我想我会帮助 2020 年遇到这个问题的人。

这对我有用,基于 node-django-hasher(没有使用它,因为依赖于 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');
}

终于解决了。因为 passlib 对我提到的解决方案的 base64 编码字符串 none 做了一些转换。我最终编写了自己的节点模块,并使用 passlib 1.7.4 哈希进行了测试。感谢@kayluhb 将我推向正确的方向!

随意使用:node-passlib