如何在 nodejs 中验证 java 生成的密码哈希 (sha-256)?

How to validate a java generated password hash (sha-256) in nodejs?

我在使用管理用户注册的 java 服务的遗留解决方案中工作。对于每个用户,java 服务生成一个密码哈希,它与使用过的盐一起存储在我们的数据库中。 java 代码使用 org.apache.shiro.crypto.hash.Sha256Hash 方法生成散列。

我现在正在尝试验证 Nodejs 服务中的同一个用户,方法是采用相同的盐来对用户输入的新密码进行哈希处理,并将其与来自数据库的同一用户的密码哈希进行比较.但是,我无法让它匹配,我不知道 why/where 它出错了。

Java 用于散列的代码片段

public static final int HASH_ITERATIONS = 1004;
public static final String HASH_ALGORITHM = Sha256Hash.SHA-256;
hashedPw = new Sha256Hash(password, new SimpleByteSource(salt), HASH_ITERATIONS).toHex();
// hashedPW and salt are stored in DB

我失败的 Nodejs 尝试:

// Getting salt and hashedPw from DB, they are
// salt = <Buffer 1e e7 1d 5a ec f2 a1 02 e9 9c 86 d7 33 04 a4 5b>
// hashedPw = f88b92d40fbc1644395d704d4f29d7e702fc8add275d5e93a52a3645611fd352

// Using crypto library, assuming length of salt is 16 bytes (given trace above)
// and that the hash algorithm corresponding to SHA-256 is 'sha256' in nodejs-crypto
const key = crypto.pbkdf2Sync(password, salt, 1004, 16, 'sha256');
console.log(key);
console.log(key.toString('hex'));

//This prints:
// <Buffer 80 10 b5 30 0e ca e0 ff 1f 97 96 1b b4 d4 d3 41>
// 8010b5300ecae0ff1f97961bb4d4d341
// which clearly doesn't match the 'hashedPw' above

我希望比我有更多加密经验的人可以帮助我看看上面的错误。

** 编辑(评论中要求的附加信息) **

(我创建了一个新的临时用户以便能够共享所有信息) 散列的密码是:myTest123

java 代码中使用的盐是:NJxGXOhrAWJ1pPNm2Hg29Q==

生成的散列密码为:63816c31d2221151edf8134de7d9b2fb4d2d189ce5fc1084b84b33c28441217c

我从 pbkdf2Sync(根据上面的 nodejs 控制台日志)得到的结果是:

<Buffer d4 9b 98 09 aa a1 92 c9 ca 70 0a 34 5b ca cb 13>
d49b9809aaa192c9ca700a345bcacb13

正如@x4rf41 在他的评论中假设的那样,不得使用 PBKDF2,而是由 SHA256 生成的散列必须每次根据迭代计数再次使用 SHA256 进行散列,参见 SimpleHash#hash。因此,可能的 NodeJS 实现是(使用您的测试数据):

const crypto = require("crypto");

// Set salt, password and iteration count
const salt = Buffer.from('NJxGXOhrAWJ1pPNm2Hg29Q==', 'base64');
const password = 'myTest123';
const hashIterations = 1004;

// Iteration 0
var value = crypto.createHash('sha256').update(salt).update(password).digest();

// Iterations 1 to hashIterations - 1
var hashIteration = 1;
while (hashIteration++ < hashIterations) {
    value = crypto.createHash('sha256').update(value).digest();
}
console.log(value.toString('hex')); // 63816c31d2221151edf8134de7d9b2fb4d2d189ce5fc1084b84b33c28441217c

NodeJS 没有为 Hash class 实现 reset 函数(因为它在 Java 和 MessageDigest#reset, which is also applied by org.apache.shiro.crypto.hash.Sha256Hash 中完成),即在调用之后digest() Hash 对象无法再使用,因此必须重新创建。

请注意,NJxGXOhrAWJ1pPNm2Hg29Q== 不是盐,而是 Base64 编码的盐。