How does digest.update(salt) in the getHash(...)
method work in the code example below? I need to duplicate the logic in PHP. The testHash()
method has some embedded test values. I can get a match if I comment out digest.update(salt)
. I've tried the following combination in PHP to get a match with no luck (pseudocode):
sha256($salt.$pass)
sha256($pass.$salt)
sha256($pass.sha256($salt))
sha256($salt.sha256($pass))
sha256(sha256($pass).sha256($salt))
sha256(sha256($salt).sha256($pass))
Code:
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();
}
}
EDIT
I've added the PHP code I've been using. It's not ideal in that I don't enumerate all the cases I've tested. Stepping through the debugger in Netbeans with an rt.jar file that I compiled with -g it looks like it's being stored as $salt.$pass. Using the PHP code I am not able to get a match.
PHP Code:
<?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";
UPDATE
I've been glued to the debugger in Netbeans for hours now trying to figure out what's happening when digest.update($salt)
is called. MessageDigestSPI is the key. engineUpdate(byte[] input, int offset, int len)
is called but I can't find the implementation. All the engineUpdate methods might be pointing to engineUpdate(ByteBuffer input)
but I can't confirm. I've done Java work before, but it was years ago. I've tried every I've hex2bin'ed, packed, unpacked, and Base64'ed every which way with no luck :( I'll keep you all posted.