1

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?

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Potocpe1
  • 35
  • 5
  • Note that there is this idiomatic thread about the duplicate topic: [Convert a string representation of a hex dump to a byte array using Java?](https://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java). Just in case you need a solution and do not want to wait for a fix of your approach. – Zabuzard Sep 09 '20 at 19:21
  • See the [following answer](https://stackoverflow.com/a/140592/2411243) in the linked thread, comment section. It explains it. – Zabuzard Sep 09 '20 at 19:22
  • Thank you for both quick answers! It helped me to understand the reason and find solution (although I saw the thread when I looked for the solution). – Potocpe1 Sep 09 '20 at 19:30

2 Answers2

1

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.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
1

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.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138