Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用PBKDF2在Java和Ruby中生成相同的安全哈希_Java_Ruby_Hash_Pbkdf2 - Fatal编程技术网

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

如何使用PBKDF2在Java和Ruby中生成相同的安全哈希,java,ruby,hash,pbkdf2,Java,Ruby,Hash,Pbkdf2,我正在将一个web应用程序从Ruby移植到Java,并希望允许用户在不重置密码的情况下登录。以下是使用pbkdf2 gem生成哈希的Ruby代码: PBKDF2.new { |p| p.password = password p.salt = salt p.iterations = 10000 }.hex_string 读取RubyGem的源代码时,它使用OpenSSL::Digest.new(“sha256”)作为默认哈希函数,并生成32字节的值,该值使用“unpack”(“H*

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

PBKDF2.new { |p|
  p.password = password
  p.salt = salt
  p.iterations = 10000
}.hex_string
读取RubyGem的源代码时,它使用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十六进制字符串编码,它们的工作原理相同,因此问题似乎出在哈希算法中,或者字符串转换为字节数组的方式中。

问题在于迭代次数。如果在Java中将其更改为10000而不是正在使用的1000,则会得到与Ruby相同的结果:

    PBEKeySpec spec = new PBEKeySpec(chars, saltBytes, 10000, 256);
补充说明:

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

另外,最好不要依赖于
biginger.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使用的相同字符集)。

您的Ruby代码具有
p.iterations=10000
。我没有看到你的Java中有10000个。哇,我错过了数字中额外的“0”。谢谢我不敢相信我错过了迭代中额外的“0”。也谢谢你的附加说明!