在计算可序列化对象与字符串的 md5 时得到不同的结果

Getting different results while computing md5 for Serializable object vs string

我想计算任何 Serilizable 对象的 md5,这是通过以下函数完成的。

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
 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?)

ObjectOutputStream增加了一个header,所以你传递的Serializable实际上并不代表"water",当你得到字节数组的时候。打印出 baos.toString() 来验证。您可以扩展 ObjectOutputStream 并覆盖 writeStreamHeader 方法,或者使用数据的子字符串调用 md.digest,即 md.digest(baos.substring(7).getBytes())(或类似的东西)。一旦消化的实际数据是 "water",哈希值将是正确的。

正如 Terje 所说,

ObjectOutPutStream 添加了一个header,你可以验证使用

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")); 

    }

无需创建所有 ByteArrayOutputStream 和 ObjectOutputStream,您可以简单地使用

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

将字节数组写入 MessageDigest。

谢谢