在Node.js中复制Java密码散列代码(PBKDF2WithHmacSHA1)

时间:2015-12-25 11:06:02

标签: javascript java node.js hash pbkdf2

编辑:我的问题已更新,请查看此帖子底部的最新一期。我把剩下的人留给想要阅读整个故事的人:)

我一直致力于将一个小型Java应用程序转换为Node.js,这在很大程度上一直很顺利。我必须查找很多Java函数来弄清楚它们的作用以及如何在Node中复制它们的行为(因为我几乎没有任何Java经验),但我现在已经完成了大部分功能。

不幸的是,有一点我似乎无法正常工作。它是一种用于生成密码哈希的方法,使用一组在Node中似乎不存在的高级Java特定函数。我已经尝试了两天才能完成这项工作,但我无法得到我想要的结果。

这是原始的Java代码:

public static String hashPassword(final String password, final String salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    final char[] passwordChars = password.toCharArray();
    final byte[] saltBytes = salt.getBytes();
    final PBEKeySpec spec = new PBEKeySpec(passwordChars, saltBytes, 1000, 192);
    final SecretKeyFactory key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    final byte[] hashedPassword = key.generateSecret(spec).getEncoded();
    return String.format("%x", new BigInteger(hashedPassword));
}

注意:盐是固定值,它不是随机的。我知道这不应该是这样,但这就是应用程序的设置方式。因此,由于Java代码总是得到相同的结果,因此应该可以在Node中获得相同的结果。

我尝试使用crypto.pbkdf2,使用看似相似的各种密码,但这些都给了我与Java代码不同的结果。所以我想我会问这里,看看是否有人知道该怎么做,或者对如何处理这个问题有任何建议。

请注意(正如我所说)我不了解Java的问题,所以让我这么做的困难可能来自这样一个事实:我很难掌握这个方法中发生的事情,并且谷歌搜索所使用的各种函数给出了相互矛盾的答案,而且大多数只是表明其他人也很难用它们。

所以我实际上有三个问题要求:

  1. 是否可以在Node.js中复制,或者Java是否使用Node中不存在的功能?
  2. 拥有更多Java经验的人是否可以解释此代码中的各个行,以及每个行的作用?最好是以某种程度的Node.js体验(和一些PHP),但从未使用过Java的人会理解:)
  3. 如果有人知道,我正在寻找哪种Node功能?我可以使用内置的加密模块来完成,还是需要额外的模块?
  4. 最后,在你说“只实现一个特定于节点的散列算法”之前(这将是更容易的选择),我不能这样做,因为这将用于已经包含这些散列密码的现有数据库也被其他现有的Java应用程序使用。目前无法更改其他应用程序或数据库。

    更新:我得到了一个非常有用的答案,现在我在我的Node.js代码中得到了这个:

    hashPassword = function(password, salt){
        crypto.pbkdf2(password, new Buffer(salt), 1000, 24, 'sha1', function(err, key){
    
        }
    }
    

    那就是我再次陷入困境的地方。我无法从密钥中获取所需的字符串值。我用google搜索了一下,发现Java代码中的String.format行将BigInteger转换为十六进制整数,但我似乎无法得到正确的值。

    • 我只是尝试了key.toString('hex')但是没有用。
    • 我找到了这个node-biginteger模块,并尝试了BigInteger.fromBuffer(1, key).toString(24)及其中的一些变体,但它仍然给我一个与Java应用程序截然不同的结果。

    非常感谢有关如何从缓冲区获取正确字符串值的任何帮助。

    Update2 :我终于让我的应用程序工作了,因为事实证明它是一个输出坏哈希的外部模块。实现加密模块正确修复它。

2 个答案:

答案 0 :(得分:2)

这些参数生成相同的缓冲区:

crypto.pbkdf2('test', 'salt', 1000, 24, 'sha1', function(err, key) {});

剩下的就是以相同的方式格式化字符串。这可能有点问题,因为BigInteger已签名,因此您也应该考虑签名。

您可以使用bn.js执行以下操作:

function format(key) {
  if (key[0] >>> 7 === 0) {
    return key.toString('hex');
  }

  return '-' + new BN(key.toString('hex'), 16).notn(192).add(new BN(1)).toString(16);
}

bn.js不会将前导位解释为符号,因此您必须先检查它,然后根据two's complement表示转换为字符串。

答案 1 :(得分:0)

我需要让它与节点6一起工作,事实证明,事情变得更简单(不需要bigints)。但是,如果没有vkurchatkin的原始答案,我绝不会想到这一点:

console.log(hashPassword('password', 'salt').toString('hex'));

function hashPassword(password, salt) {
    return crypto.pbkdf2Sync(password, Buffer.from(salt, 'hex'), 1000, 24, 'sha1');
}