59

I'm trying to get the SHA256 of a string in Android.

Here is the PHP code that I want to match:

echo bin2hex(mhash(MHASH_SHA256,"asdf"));
//outputs "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"

Now, in Java, I'm trying to do the following:

            String password="asdf"
            MessageDigest digest=null;
    try {
        digest = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
       digest.reset();
       try {
        Log.i("Eamorr",digest.digest(password.getBytes("UTF-8")).toString());
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

But this prints out: "a42yzk3axdv3k4yh98g8"

What did I do wrong here?


Solution thanks to erickson:

 Log.i("Eamorr",bin2hex(getHash("asdf")));

 public byte[] getHash(String password) {
       MessageDigest digest=null;
    try {
        digest = MessageDigest.getInstance("SHA-256");
    } catch (NoSuchAlgorithmException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
       digest.reset();
       return digest.digest(password.getBytes());
 }
static String bin2hex(byte[] data) {
    return String.format("%0" + (data.length*2) + "X", new BigInteger(1, data));
}
7
  • 1
    I think your problem may be the getBytes(UTF-8). Try just getBytes(). Commented Aug 23, 2011 at 19:07
  • 5
    Why should anyone ever use getBytes() without specifying the encoding? Commented Aug 23, 2011 at 19:15
  • 5
    @Eamorr: Could you put the solution in an answer instead of the question, please? Commented Aug 23, 2011 at 19:17
  • The code you have as the solution does not work... any help? Commented Mar 14, 2012 at 21:06
  • 1
    A clean answer is written up here: stackoverflow.com/questions/9661008/… Commented Jan 31, 2014 at 7:42

5 Answers 5

35

The PHP function bin2hex means that it takes a string of bytes and encodes it as a hexadecimal number.

In the Java code, you are trying to take a bunch of random bytes and decode them as a string using your platform's default character encoding. That isn't going to work, and if it did, it wouldn't produce the same results.

Here's a quick-and-dirty binary-to-hex conversion for Java:

static String bin2hex(byte[] data) {
    StringBuilder hex = new StringBuilder(data.length * 2);
    for (byte b : data)
        hex.append(String.format("%02x", b & 0xFF));
    return hex.toString();
}

This is quick to write, not necessarily quick to execute. If you are doing a lot of these, you should rewrite the function with a faster implementation.

Sign up to request clarification or add additional context in comments.

5 Comments

Actually, new BigInteger(1, data).toString(16) is all you need in the case of data from a digest function, because it's guaranteed that no nibble will be full of 0s.
@ClassStacker What's the SHA-1 hash of 0x35326b9705d136d0d1b5efa92d440f3171f1b711?
@erickson I'm definitely to be blamed for claiming no nibble would ever be zero anyway, but here you go; according to python it's \x00P\xd5\rv\xc8\x15u\x84*\xf3\x1d\xc3L\x9b\x14{\xedX? and I stand here guilty. Thanks for pointing this out.
@ClassStacker No problem. SHA-1 and SHA-2 hashes, and I assume any cryptographic digest, can produce zero nybbles and bytes, including leading zeros. I didn't expect otherwise, but when you said it was impossible, it didn't take long to verify my assumption.
@erickson That may not be a problem for you and me, but I presume it has the potential to lead to occasional trouble elsewhere. ;)
27

You are along the right lines, but converting the bytes is a little more complicated. This works on my device:

// utility function
    private static String bytesToHexString(byte[] bytes) {
        // http://stackoverflow.com/questions/332079
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

// generate a hash

    String password="asdf";
    MessageDigest digest=null;
    String hash;
    try {
        digest = MessageDigest.getInstance("SHA-256");
        digest.update(password.getBytes());

        hash = bytesToHexString(digest.digest());

        Log.i("Eamorr", "result is " + hash);
    } catch (NoSuchAlgorithmException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

Source: bytesToHexString function is from the IOSched project.

1 Comment

Careful: the bytesToHexString function you took from IOSched project returns the String in lower-case format. When chaining it by doing SHA256(SHA256...(SHA256(input)...) you would get different results from implementations that return the String in upper-case format. This can easily be addressed by chainging the responsible line to String hex = Integer.toHexString(0xFF & bytes[i]).toUpperCase();
9

Complete answer with use example, thanks to erickson.

public static String getSha256Hash(String password) {
    try {
        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        }
        digest.reset();
        return bin2hex(digest.digest(password.getBytes()));
    } catch (Exception ignored) {
        return null;
    }
}

private static String bin2hex(byte[] data) {
    StringBuilder hex = new StringBuilder(data.length * 2);
    for (byte b : data)
        hex.append(String.format("%02x", b & 0xFF));
    return hex.toString();
}

Example of use:

Toast.makeText(this, Utils.getSha256Hash("123456_MY_PASSWORD"), Toast.LENGTH_SHORT).show();

Comments

2
private fun stringToSha256(input: String): String {
    val bytes = input.toByteArray()
    val md = MessageDigest.getInstance("SHA-256")
    val digest = md.digest(bytes)

    // Convert the byte array to a hexadecimal string
    val result = StringBuilder()
    for (byte in digest) {
        result.append(String.format("%02x", byte))
    }

    return result.toString()
}

Comments

1

i know this has been answered but i found a Hashing Library at android arsenal and its very easy,simple and just one line of code. can hash MD5, SHA-1, SHA-256, SHA-384, or SHA-512.

  1. first add this to your gradle and sync

    implementation 'com.github.1AboveAll:Hasher:1.2'

  2. start hasing

    Hasher.Companion.hash("Hello",HashType.SHA_1);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.