【问题标题】:Replicating Java password hashing code in Node.js (PBKDF2WithHmacSHA1)在 Node.js (PBKDF2WithHmacSHA1) 中复制 Java 密码哈希代码
【发布时间】:2016-03-31 11:03:39
【问题描述】:

编辑:我的问题已更新,请查看这篇文章的底部以获取最新问题。我把剩下的留给想要阅读整个故事的人:)

我一直致力于将一个小型 Java 应用程序翻译成 Node.js,大部分情况下进展顺利。我不得不查找很多 Java 函数来弄清楚它们的作用以及如何在 Node 中复制它们的行为(因为我几乎没有任何 Java 经验),但我现在已经得到了大部分功能。

不幸的是,有一点我似乎无法开始工作。它是一种用于生成密码哈希的方法,使用一组在 Node.js 中似乎不存在的高级 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 函数来使其正常工作?我可以使用内置的加密模块吗?还是需要额外的模块?

最后,在您说“只实现特定于节点的哈希算法”(这将是更简单的选择)之前,我不能这样做,因为这将用于已经包含这些哈希密码的现有数据库,并且也被其他现有的 Java 应用程序使用。更改其他应用程序或数据库目前不是一种选择。

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

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

    }
}

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

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

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

Update2:我终于让我的应用程序正常工作了,因为它是一个输出错误哈希值的外部模块。实施加密模块正确修复它。

【问题讨论】:

    标签: javascript java node.js hash pbkdf2


    【解决方案1】:

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

    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 表示转换为字符串。

    【讨论】:

    • Java 代码使用 192 的长度,但在您的代码中您设置了 24 的长度,有什么具体原因吗?
    • 在 java 中以位为单位,在 node.js 中 - 以字节为单位
    • 啊。这很清楚:) 我尝试了crypto.pbkdf2,但我将它设置为 192,因为这是我在 Java 代码中看到的,显然这给了我非常不同的结果。
    • 我现在卡在 BigInteger 上,我用谷歌搜索了一些,发现 Java 方法的最后一行将缓冲区转换为十六进制整数。简单地调用.toString('hex') 不起作用,然后我找到this node-biginteger module 并尝试使用加密函数中的密钥BigInteger.fromBuffer(1, key).toString(24),但它也没有给我我需要的结果。关于如何获取字符串值的任何提示?
    • 仍然一无所有:(您的format 函数只是给了我key.toString('hex') 的结果,这不是我需要的值。我接受我需要该函数来处理有符号值,但是Java 代码肯定还在对数据做其他事情,我只是不知道是什么。我检查了一下,hashPassword 的返回值没有发生其他任何事情,它只是以System.out.println(password); 结束。
    【解决方案2】:

    我需要让它与节点 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');
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-27
      • 1970-01-01
      • 2014-07-28
      • 2018-03-13
      • 1970-01-01
      • 2018-09-10
      • 2011-04-30
      • 2012-07-07
      相关资源
      最近更新 更多