Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create an SHA512 digest string in Java using bouncy castle?

This unit test is failing:

    public void testDigest() throws NoSuchAlgorithmException {
    String hashExpected = "150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197";
    MessageDigest md = new MessageDigest();
    String hashActual = new String(md.digest("hi"));
    Assert.assertEquals(hashExpected, hashActual);
}

Below is my implementation of my MessageDigest class:


import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.io.DigestInputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class MessageDigest { private Digest messageDigest;

public MessageDigest() throws NoSuchAlgorithmException {
    Security.addProvider(new BouncyCastleProvider());
    messageDigest = new SHA512Digest();
}

public byte[] digest(String message) {
    byte[] retValue = new byte[messageDigest.getDigestSize()];
    messageDigest.update(message.getBytes(), 0, message.length());
    messageDigest.doFinal(retValue, 0);
    return retValue;
}

}

The test fails with the following reason:


junit.framework.ComparisonFailure: expected:<150a14ed5bea6cc731cf86c41566ac427a8db48ef1b9fd626664b3bfbb99071fa4c922f33dde38719b8c8354e2b7ab9d77e0e67fc12843920a712e73d558e197> but was:<
í[êlÇ1φÄf¬Bz�´Žñ¹ýbfd³¿»™¤É"ó=Þ8q›ŒƒTâ·«�wàæÁ(C’
q.sÕXá

I have a feeling I'm not using the right encoding scheme when I convert my byte[] digest into a string. Any help would be appreciated.

like image 780
Lee Warner Avatar asked Feb 05 '10 15:02

Lee Warner


3 Answers

The value you're expecting is a Hex-encoded value. You're creating a String based on the raw bytes, which won't work.

You should use the standard Java Crypto API whenever possible instead of BouncyCastle specific APIs.

Try the following (the Hex library comes from commons-codec):

Security.addProvider(new BouncyCastleProvider());

String data = "hello world";

MessageDigest mda = MessageDigest.getInstance("SHA-512", "BC");
byte [] digesta = mda.digest(data.getBytes());

MessageDigest mdb = MessageDigest.getInstance("SHA-512", "BC");
byte [] digestb = mdb.digest(data.getBytes());

System.out.println(MessageDigest.isEqual(digesta, digestb));

System.out.println(Hex.encodeHex(digesta));
like image 108
Kevin Avatar answered Nov 01 '22 06:11

Kevin


Just an addition to Kevin's answer: Since Java 5, you can use String.format("%0128x", new BigInteger(1, digesta)) instead of commons-codec to format the byte array as a 128 digit hex encoded number with leading zeros.

like image 26
jarnbjo Avatar answered Nov 01 '22 07:11

jarnbjo


Yes, you need to turn your byte array into a hex string. :-) Look into Apache Commons Codec, especially the Hex class.

like image 41
Chris Jester-Young Avatar answered Nov 01 '22 07:11

Chris Jester-Young