【问题标题】:How do I replicate this PHP hashing implementation in Node.js?如何在 Node.js 中复制这个 PHP 哈希实现?
【发布时间】:2021-07-03 14:10:30
【问题描述】:

我正在尝试在最初用 PHP (7.2) 编写的 node.js (LTS latest--14.x) 中重新创建密码哈希实现。我相信我编写的 node.js 实现应该做同样的事情;但是,在循环中第一次通过哈希之后,node.js 的实现会有所不同。我在这里错过了什么?

PHP 实现(我无法更改它,因为它是 Web 框架的一部分,并且现有的身份验证依赖于保持不变的散列机制):

$algo = "sha512";
$salt = "someSalt";
$password = 'somePassword';
$count = 32768;

$hash = hash($algo, $salt . $password, TRUE);
// $hash is the same as in the corresponding line in the node.js implementation
do {
  $hash = hash($algo, $hash . $password, TRUE);
  // $hash differs from the node.js implementation after the first pass here... why?
} while (--$count);

Node.js 实现:

const crypto = require('crypto');

const algorithm = 'sha512';
const salt = 'someSalt';
const password = 'somePassword';
let count = 32768;

let hash = crypto
        .createHash(algorithm)
        .update(salt + password)
        .digest('binary');
// hash is the same as in the PHP implementation here
do {
  hash = crypto.createHash(algorithm).update(hash + password).digest('binary');
  // hash differs between the two implementations after the first pass here... why?
} while (--count);

编辑:更新以显示原始 Node.js 实现,其中我没有对传递给 update() 的数据进行字符串化。

【问题讨论】:

  • 试试看.digest('hex')
  • PHP 中的原始实现输出为二进制,而不是十六进制(参见hash() 函数的最后一个参数是TRUE)。编辑:我测试它只是为了确定,它肯定会产生不同的哈希值。
  • 看看你的节点更新它字符串化的二进制输出。在 PHP 版本中你没有。我会尽可能在 NODE 中使用 .digest('hex'),并在 PHP 端使用 bin2hex()。这样您就可以保留二进制文件并使用 HEX 值
  • 我已经提供了一个答案以及我的测试输出。 PHP 7.4.16 和节点 14.16.0
  • 在 NodeJS 代码中,binary' 必须指定为 update() 调用中的第二个参数(默认为 UTF8,这会破坏数据,至少对于第二次和后续的 update() 调用) )。然后两个代码在我的机器上返回相同的结果。

标签: javascript php node.js cryptography


【解决方案1】:

扩展我的评论,我认为以下可能有效。

节点:

const crypto = require('crypto');

const algorithm = 'sha512';
const salt = 'someSalt';
const password = 'somePassword';
let count = 32768;

let hash = crypto
        .createHash(algorithm)
        .update(String(salt) + String(password))
        .digest('hex');
// hash is the same as in the PHP implementation here
do {
  hash = crypto.createHash(algorithm).update(String(hash) + String(password)).digest('hex');
  // hash differs between the two implementations after the first pass here... why?
} while (--count);


console.log(hash);

PHP 代码:

$algo = "sha512";
$salt = "someSalt";
$password = 'somePassword';
$count = 32768;

$hash = bin2hex(hash($algo, $salt . $password, TRUE));
// $hash is the same as in the corresponding line in the node.js implementation
do {
  $hash = bin2hex(hash($algo, $hash . $password, TRUE));
  // $hash differs from the node.js implementation after the first pass here... why?
} while (--$count);

var_dump($hash);

用 NODE 的输出证实了我的发现:

node nodeTest.js
df8202221e5cbff38c16a33945efa8dcb44d0e7267cdf1514cefffb3df321f69ad1d9b01cfb6360391f1de4791e26a179fd165248b4b75699cb2d3395c971351

PHP 输出:

php test.php
string(128) "df8202221e5cbff38c16a33945efa8dcb44d0e7267cdf1514cefffb3df321f69ad1d9b01cfb6360391f1de4791e26a179fd165248b4b75699cb2d3395c971351"

【讨论】:

  • 我刚刚发布这个是为了回应另一条评论,但很遗憾我无法修改原始的 PHP 实现,因为它是 Web 框架的一部分,并且会破坏现有的身份验证。我只是试图在 Node.js 中复制身份验证机制,以便我可以从 PHP Web 框架过渡。
【解决方案2】:

在循环中进行散列时,我必须将'binary' 传递给update(),因为提供的数据是二进制的。

// The data being passed to update() here is string (update defaults to utf-8, I believe).
let hash = crypto
        .createHash(algorithm)
        .update(salt + password)
        .digest('binary');
do {
  // The data being passed to update() is binary.
  hash = crypto.createHash(algorithm).update(hash + password, 'binary').digest('binary');
} while (--count);

感谢:@Topaco 为我的问题找到了解决方案!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-25
    • 2020-06-18
    • 2019-10-20
    • 1970-01-01
    • 2016-05-17
    • 2011-05-08
    • 2016-03-31
    • 2013-01-29
    相关资源
    最近更新 更多