Potocpe1
Potocpe1

Reputation: 35

String hex hash to bytes

I have String hash in hex form ("e6fb06210fafc02fd7479ddbed2d042cc3a5155e") and I would like to compare it to crypt.digest(). One way, which works fine, is to convert crypt.digest() to hex, but I would like to avoid multiple conversions and rather convert hash from hex form (above) to byte array.

What I tried was:

byte[] hashBytes = new BigInteger(hash, 16).toByteArray();

but it does not match with crypt.digest(). When I convert hashBytes back to hex I get "00e6fb06210fafc02fd7479ddbed2d042cc3a5155e".

The leading zeros seem to be the reason why I fail to match byte arrays. Why do they occur? How can I get the same result using crypt.digest() and toByteArray?

Upvotes: 1

Views: 1247

Answers (2)

Zabuzard
Zabuzard

Reputation: 25933

The answer can be found in the following answer from a thread about the highly related question Convert a string representation of a hex dump to a byte array using Java?:

The issue with BigInteger is that there must be a "sign bit". If the leading byte has the high bit set then the resulting byte array has an extra 0 in the 1st position. But still +1.

– Gray Oct 28 '11 at 16:20

Since the first bit has a special meaning (indicating the sign, 0 for positive, 1 for negative), BigInteger will prefix the data with an additional 0 in case your data started with a 1 on the high bit. Otherwise it would be interpreted as negative although it was not negative to begin with.

I.e. data like

101110

is turned into

0101110

You could easily undo this manually by using Arrays.copyOfRange(data, 1, data.length) if it happens.


However, instead of fixing that code, I would suggest using one of the other solutions posted in the linked thread. They are cleaner and easier to read and maintain.

Upvotes: 1

Joop Eggen
Joop Eggen

Reputation: 109613

The reason for the extra 00 is that e6 has it high (sign) bit set. A redundant byte 00 makes it an unsigned value for BigInteger.

    String hash = "e6fb06210fafc02fd7479ddbed2d042cc3a5155e";
    byte[] hashBytes = new BigInteger(hash, 16).toByteArray();
    hashBytes = hashBytes.length > 1 && hashBytes[0] == 0
        ? Arrays.copyOfRange(hashBytes, 1, hashBytes.length) : hashBytes;
    System.out.println(Arrays.toString(hashBytes));

The question arises, what if the hash actually starts with a 00? Then you need the hash length, or do a lenient comparison.

Upvotes: 1

Related Questions