Peter Tillemans
Peter Tillemans

Reputation: 35341

Which SHA-256 is correct? The Java SHA-256 digest or the Linux commandline tool

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 the following (I need the -n to not add a newline) :

echo -n "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!

Upvotes: 25

Views: 15774

Answers (7)

gswierczynski
gswierczynski

Reputation: 4173

You can also get the right result using this:

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

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

BigInteger bI = new BigInteger(1, hash);

System.out.println(bI.toString(16));

Upvotes: 0

lpinto.eu
lpinto.eu

Reputation: 2127

Using @paxdiablo idea had problem with big number as it appear as negative, so

Instead of:

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

you could do:

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

And read @Sean Owen answer.

Upvotes: 1

yegong
yegong

Reputation: 749

You still need "echo -n" to prevent the trailing \n

Upvotes: 4

paxdiablo
paxdiablo

Reputation: 882146

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));
}

Upvotes: 10

David M
David M

Reputation: 72900

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.

Upvotes: 7

Sean Owen
Sean Owen

Reputation: 66896

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".

Upvotes: 29

user308323
user308323

Reputation:

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

Upvotes: 2

Related Questions