farmdve farmdve - 1 month ago 13
Android Question

Cannot output correct hash in Java. What is wrong?

In my Android app I have a SHA256 hash which I must further hash with the RIPEMD160 message digest algorithm.

I can output the correct sha256 and ripemd160 hash of any string, but when I try to hash the sha256 hash with ripemd160 I get a hash which is incorrect.

According to online hash calculators, the SHA256 value of the string 'test'(all lowercase) is:

9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08


And the RIPEMD160 value of the string 'test' is:

5e52fee47e6b070565f74372468cdc699de89107


The value from hashing the resulting sha256 hash with ripemd160 according to online calcs is:

4efc1c36d3349189fb3486d2914f56e05d3e66f8


And the one my app gives me is:

cebaa98c19807134434d107b0d3e5692a516ea66


which is obviously wrong.

Here is my code:

public static String toRIPEMD160(String in)
{
byte[] addr = in.getBytes();
byte[] out = new byte[20];
RIPEMD160Digest digest = new RIPEMD160Digest();
byte[] sha256 = sha256(addr);
digest.update(sha256,0,sha256.length);
digest.doFinal(out,0);
return getHexString(out);
}

public static byte[] sha256(byte[] data)
{
byte[] sha256 = new byte[32];
try
{
sha256 = MessageDigest.getInstance("SHA-256").digest(data);
}
catch(NoSuchAlgorithmException e)
{}

return sha256;
}


For the ripemd160 algorithm, you need bouncycastle and java.security.MessageDigest for sha256.

Answer

Your hash is working fine. The problem is that the online calculators that you're using are treating your input:

9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

as a string instead of an array of bytes. In other words, it's treating each character as a byte instead of parsing character pairs as bytes in hexadecimal. If I give this as a string to online calculators, I indeed get exactly what you got:

4efc1c36d3349189fb3486d2914f56e05d3e66f8

However, you're treating the output as an array of bytes instead of a String and that's giving you different results. You should encode your raw SHA256 hash as a string, then pass the encoded string to the hash function. I see you have a getHexString method, so we'll just use that.

public static String toRIPEMD160(String in) {
    try {
        byte[] addr = in.getBytes();
        byte[] out = new byte[20];
        RIPEMD160Digest digest = new RIPEMD160Digest();

        // These are the lines that changed
        byte[] rawSha256 = sha256(addr);
        String encodedSha256 = getHexString(rawSha256);
        byte[] strBytes = encodedSha256.getBytes("UTF-8");
        digest.update(strBytes, 0, strBytes.length);

        digest.doFinal(out, 0);
        return getHexString(out);
    } catch (UnsupportedEncodingException ex) {
        // Never happens, everything supports UTF-8
        return null;
    }
}

If you want to know it's working, take the value of encodedSha256 and put that into an online hash calculator. As long as the calculator uses UTF-8 encoding to turn the string into a byte array, it will match your output.

Comments