user93796
user93796

Reputation: 18389

Getting different results while computing md5 for Serializable object vs string

I want to compute md5 of any Serilizable object, which is done by following function.

public static String getMd5Hash(Serializable object) {
        try {
            return getChecksum(object, "MD5");
        } catch (Exception e) {
            throw new RmsException("Exception while generating md5 hash", e);
        }
    }



public static String getMd5Hash(Serializable object) {
            try {
                return getChecksum(object, "MD5");
            } catch (Exception e) {
                throw new RuntimeException("Exception while generating md5 hash", e);
            }
        }

    private static String getChecksum(Serializable object, String algorithm)
        throws IOException, NoSuchAlgorithmException {
        try (
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos)
        ) {
            oos.writeObject(object);
            MessageDigest md = MessageDigest.getInstance(algorithm);
            byte[] theDigest = md.digest(baos.toByteArray());
            return DatatypeConverter.printHexBinary(theDigest);
        }
    }

Test

@Test
 public void getMd5Hash() {
        String actual = CryptoUtils.getMd5Hash("water");

        Assert.assertEquals("9460370bb0ca1c98a779b1bcc6861c2c", actual);
}

OP

Expected :9460370bb0ca1c98a779b1bcc6861c2c (actual md5 for string water)
Actual   :37F7DBD142DABF05ACAA6759C4D9E96C (Why the diff?)

Upvotes: 1

Views: 1056

Answers (2)

Alpesh Jikadra
Alpesh Jikadra

Reputation: 1722

As Terje says,

ObjectOutPutStream adds a header, you can verify that using

public static String getChecksum(Serializable object, String algorithm)
            throws IOException, NoSuchAlgorithmException {

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos)) {

            oos.writeObject(object);
            oos.flush();
            MessageDigest md = MessageDigest.getInstance(algorithm);
            md.update(object.toString().getBytes());
            byte[] theDigest = md.digest();
            System.out.println("Without Object output stream="+DatatypeConverter.printHexBinary(theDigest));


            md.reset();
            System.out.println("object="+object+ " Written to ByteArray is="+baos.toString());
            md.update(baos.toByteArray());
            theDigest = md.digest();
            return DatatypeConverter.printHexBinary(theDigest);
        }
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
        System.out.println(getChecksum("water", "MD5")); 

    }

Instead of creating all ByteArrayOutputStream and ObjectOutputStream, you can simple use

md.update(object.toString().getBytes());

To write byte array to MessageDigest.

Thanks

Upvotes: 1

Terje
Terje

Reputation: 1763

The ObjectOutputStream adds a header, so the Serializable you are passing does not actually represent "water" when you get the byte array. Print out baos.toString() to verify. You can either extend ObjectOutputStream and override the writeStreamHeader method, or call md.digest with the substring of the data, ie md.digest(baos.substring(7).getBytes()) (or something thereabouts). Once the actual data digested is "water", the hash will be correct.

Upvotes: 2

Related Questions