getHash(...)
方法中的digest.update(salt)如何在下面的代码示例中工作?我需要在PHP中复制逻辑。 testHash()
方法有一些嵌入的测试值。如果我发表评论digest.update(salt)
,我可以得到一个匹配。我在PHP中尝试了以下组合以获得没有运气的匹配(伪代码):
sha256($salt.$pass)
sha256($pass.$salt)
sha256($pass.sha256($salt))
sha256($salt.sha256($pass))
sha256(sha256($pass).sha256($salt))
sha256(sha256($salt).sha256($pass))
代码:
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Owasp {
private final static int ITERATION_NUMBER = 5;
public void testhash() throws IOException, NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] bSalt = base64ToByte("123456");
byte[] bDigest = getHash(ITERATION_NUMBER, "somepass", bSalt);
String sDigest = byteToBase64(bDigest);
System.out.println(sDigest);
}
public byte[] getHash(int iterationNb, String password, byte[] salt) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.reset();
digest.update(salt);
byte[] input = digest.digest(password.getBytes("UTF-8"));
for (int i = 0; i < iterationNb; i++) {
digest.reset();
input = digest.digest(input);
}
return input;
}
public static byte[] base64ToByte(String data) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
return decoder.decodeBuffer(data);
}
public static String byteToBase64(byte[] data) {
BASE64Encoder endecoder = new BASE64Encoder();
return endecoder.encode(data);
}
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException, IOException {
Owasp t = new Owasp();
t.testhash();
}
}
修改
我添加了我一直在使用的PHP代码。这并不理想,因为我没有列举我测试过的所有案例。使用我用-g编译的rt.jar文件逐步调试Netbeans中的调试器,看起来它被存储为$ salt。$ pass。使用PHP代码我无法获得匹配。
PHP代码:
<?php
//Without salt
$pass = "somepass";
$hash = hash('sha256', $pass, true);
for($i = 0; $i < 5; $i++) {
$hash = hash('sha256', $hash, true);
}
echo "Java output without salt: " . "r+G0EnbjURjk99+wMvjnJV51d/tVX8tAn+7VAUCPXRY=" . "\n";
echo "PHP output without salt : " . base64_encode($hash) . "\n";
//With salt
$pass = "somepass";
$salt = "123456";
//I've tried all sorts of combinations and manipulation.
$hash = hash('sha256', $salt.$pass, true);
for($i = 0; $i < 5; $i++) {
$hash = hash('sha256', $hash, true);
}
echo "Java output with salt: " . "vxZP4vmc+dixEhsZW58+zViLn7XXymirCP7kbl2KtT0=" . "\n";
echo "PHP output with salt : " . base64_encode($hash) . "\n";
更新
我已经被Netbeans中的调试器搞砸了几个小时,现在试图找出调用digest.update($salt)
时发生的事情。 MessageDigestSPI是关键。 engineUpdate(byte[] input, int offset, int len)
被调用,但我找不到实现。所有engineUpdate方法都可能指向engineUpdate(ByteBuffer input)
,但我无法确认。我以前做过Java工作,但是几年前。我已经尝试了每一个我的hex2bin'ed,打包,解压缩和Base64'ed每一个方式没有运气:(我会让你们全部张贴。
答案 0 :(得分:0)
该算法基本上是hash(hash(hash(hash(...hash(password)...)))))
,是 iterationNb 参数所指示的次数。
使用salt的正确方法是将其与密码连接,然后对其进行散列。这是通过执行digest.update(salt)
在您的代码中完成的,然后使用密码调用digest。它基本上与以下相同:
String saltedPassword = password + new String(salt, "UTF-8");
byte[] input = digest.digest(saltedPassword.getBytes("UTF-8"));
当然,与任何适当的盐一样,您需要将其与散列密码一起存储,以便将来验证它。
您可以获得有关salt如何存储密码哈希值at this Wikipedia link的更多信息。此外,在this other StackOverflow question.
存储密码时使用salt的一些最佳做法