views:

285

answers:

4

When I calculate in Java an SHA-256 of a string with the following method

public static void main(String[] args) throws NoSuchAlgorithmException {

    MessageDigest md = MessageDigest.getInstance("SHA-256");

    byte[] hash = md.digest("password".getBytes());

    StringBuffer sb = new StringBuffer();
    for(byte b : hash) {
        sb.append(Integer.toHexString(b & 0xff));
    }

    System.out.println(sb.toString());
}

I get :

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8

on the commandline I do :

echo "password" | sha256sum

and get

5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

if we compare these more closely I find 2 subtle differences

5e884898da2847151d0e56f8dc6292773603dd6aabbdd62a11ef721d1542d8
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

or :

5e884898da28   47151d0e56f8dc6292773603d   d6aabbdd62a11ef721d1542d8
5e884898da28 0 47151d0e56f8dc6292773603d 0 d6aabbdd62a11ef721d1542d8

Which of the 2 is correct here?

Result: Both are but I was wrong...

fixed it by using :

    StringBuffer sb = new StringBuffer();
    for(byte b : hash) {
        sb.append(String.format("%02x", b));
    }

Thanks!

Blockquote

+1  A: 

The culprit is the toHexString. It appears to be outputting 6 for the value 6 whereas the sha256sum one is outputting 06. The Java docs for Integer.toHexString() state:

This value is converted to a string of ASCII digits in hexadecimal (base 16) with no extra leading 0s.

The other zeros in the string aren't being affected since they're the second half of the bytes (e.g., 30).

One way to fix it would be to change:

for(byte b : hash) {
    sb.append(Integer.toHexString(b & 0xff));
}

to:

for(byte b : hash) {
    if (b < 16) sb.append("0");
    sb.append(Integer.toHexString(b & 0xff));
}
paxdiablo
+1  A: 

The one generated by sha256sum seems correct. Your implementation seems to drop those two zeroes.

esalaka
+8  A: 

I'll take a reasonable guess: both are outputting the same digest, but in your Java code that outputs the byte[] result as a hex string, you outputting small byte values (less than 16) without a leading 0. So a byte with value "0x0d" is being written as "d" not "0d".

Sean Owen
Yep, just saw your update with code -- this is the problem. `Integer.toHexString()` will not write the leading 0. Might be easiest to just special case values less than 16 and write a '0' in front.
Sean Owen
Silly me! Thanks for the swift response! I just got lucky with my MD5 implementation. Great save...
Peter Tillemans
+1  A: 

They're both right - it's your Java code that is at fault, because it is not printing out the leading 0 for a hex value less than 0x10.

David M