当前位置: 首页 > 知识库问答 >
问题:

如何使用PBKDF2在Java和Ruby中生成相同的安全哈希

归俊
2023-03-14

我正在将一个web应用程序从Ruby移植到Java,并希望允许用户在不重置密码的情况下登录。下面是使用pbkdf2 gem生成哈希的Ruby代码:

PBKDF2.new { |p|
  p.password = password
  p.salt = salt
  p.iterations = 10000
}.hex_string

读取Ruby gem的源代码时,它使用openssl::digest.new(“sha256”)作为默认散列函数,并生成一个32字节的值,该值使用“unpack(”h*“)”转换为一个64字符串。

所以,在Java,我尝试了以下几种方法:

public String generatePasswordHash(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException
{
    char[] chars = password.toCharArray();
    byte[] saltBytes =salt.getBytes();

    PBEKeySpec spec = new PBEKeySpec(chars, saltBytes, 1000, 256);
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    byte[] hash = skf.generateSecret(spec).getEncoded();
    BigInteger bi = new BigInteger(1, hash);
    return bi.toString(16);
}

使用password=“apassword”和salt=“someSalt”测试这两段代码,我得到以下结果。

Ruby: 3fa1eb7544ca49b1f371eb17d24bf0010c433fa263a84aff7df446741371706b

Java: 77a7c0b1ea9760d0b1ef02e7a2633c40ccd7848ee4fa822ec71b5794e476f354

我测试了Ruby和Java十六进制字符串编码,它们的工作原理相同,所以问题似乎出在散列算法上,也可能出在字符串转换为字节数组的方式上。

共有1个答案

陆臻
2023-03-14

问题在于迭代的次数。如果您在Java中将它改为10,000而不是您正在使用的1,000,它将给您一个与您在Ruby中得到的结果相同的结果:

    PBEKeySpec spec = new PBEKeySpec(chars, saltBytes, 10000, 256);

附加说明:

最好确保字节是根据已知字符集从字符串中提取的。没有字符集,它使用默认字符集是什么,它可能会引起意外。

此外,最好不要依赖biginteger.toString(16),因为如果前几个字节为0,它将返回一个短于64个字符的字符串。改用string.format():

public static String generatePasswordHash(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException
{
    char[] chars = password.toCharArray();
    byte[] saltBytes =salt.getBytes(StandardCharsets.US_ASCII);

    PBEKeySpec spec = new PBEKeySpec(chars, saltBytes, 10000, 256);
    SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    byte[] hash = skf.generateSecret(spec).getEncoded();
    BigInteger bi = new BigInteger(1, hash);
    return String.format("%064x", bi);
}

(我假设salt是纯ASCII文本。您可以更改字符集,但请记住使用Ruby使用的相同字符集)。

 类似资料:
  • 问题内容: 我有一个函数可以在C#中生成MD5哈希,如下所示: 在Java中,我的函数如下所示: C#代码生成:“ 02945C9171FBFEF0296D22B0607D522D”时,Java代码生成:“ 5a700e63fa29a8eae77ebe0443d59239”。 有没有办法为相同的字节数组生成相同的md5哈希? 一经请求: 这是java中的测试代码: 这是我在C#中的代码 干杯 问题

  • 问题内容: 用Java编写的现有系统将字符串的哈希码用作其负载平衡的路由策略。 现在,我 无法修改系统, 但需要生成共享相同哈希码的字符串以测试最坏的情况。 我从命令行提供了这些字符串,并希望系统将所有这些字符串路由到同一目的地。 是否可以生成大量共享相同哈希码的字符串? 为了使这个问题更清楚: 备注:任何hashCode值都是可接受的。字符串是什么没有限制。但是它们应该彼此不同。 编辑:Stri

  • 用Java编写的现有系统使用字符串的哈希代码作为负载平衡的路由策略。 现在,我无法修改系统,但需要生成共享相同哈希代码的字符串来测试最坏的情况。 我从命令行提供这些字符串,并希望系统将所有这些字符串路由到同一个目的地。 有可能生成大量共享相同哈希代码的字符串吗? 为了明确这个问题: 备注:任何hashCode值均可接受。对字符串是什么没有限制。但它们应该彼此不同。 编辑:不接受String类的重写

  • 我正在写一个Django应用程序,需要与现有的Java播放框架应用程序一起工作。Play应用程序使用PasswordHash.java来存储密码。它以冒号分隔的格式存储密码。每个哈希都存储为::。 例如,下面是密码“测试”的条目: 在这里,我们可以通过拆分字符串并找到: 迭代次数: 盐: PBKDF2哈希:。 我修改了Django的check_密码机制以与此格式兼容,但发现它认为密码不正确。我用了

  • 我正在迁移一个使用Passlib 1.6.2生成密码哈希的平台。加密密码的代码是(调用哈希时使用轮次的默认值): 输出格式如下所示(对于密码“patient3”(无引号)): 我看得出来代表着: 算法SHA512 迭代10001 盐0DR7V7EWUMPTRFW.9Z6HKA(可能) Passlib算法是在他们的站点上定义的,它的内容如下:

  • 我将一个文件上传到Corda节点,并得到以下十六进制值作为字符串返回: 854AAE9BE6607CE0B15A70EEBEF19C553557103FB051413F2AA35E70F5B44313 现在我需要将它作为secureHash参数传递给事务构建器:txBuilder.addatTachment(??)。 如何从文件上载获得的十六进制字符串结果作为的输入参数构建安全哈希? Secure