13.4.3 报文摘要

使用报文摘要的目的是防止数据的内容被恶意篡改。当数据通过网络或其他方式传输时,有可能有第三方对数据进行拦截并篡改其中的内容。数据的接收者会在不知情的情况下使用错误的数据。报文摘要的做法是使用某种算法对原始数据进行处理,得到一个固定长度的摘要,这个摘要会随着数据一同公开出来。接收者对接收到的数据使用相同的算法计算出摘要,再与正确的摘要进行比较。如果不一致,则说明数据已经被篡改。摘要算法可以对任意长度的数据进行处理,得到的都是固定长度的摘要。报文摘要算法具有一个显著的特点,那就是要找到两段内容不同而摘要相同的数据,在计算上几乎是不可能的。这一特点保证如果数据被篡改,总是可以通过摘要的变化来检查出来。另外,摘要本身也不会暴露原始数据的任何信息。不过随着技术的进步,一些之前安全的摘要算法,也被发现有安全漏洞。

进行报文摘要的MessageDigest类的使用方式类似于之前提到的Cipher类,使用getInstance方法获取不同算法的实现。如果数据较多,那么使用update方法来分成多次进行处理。最后一次处理或数据较少时使用digest方法。代码清单13-18给出了使用常见的MD5算法计算摘要的示例。

代码清单13-18 使用MD5算法计算摘要的示例


MessageDigest md=MessageDigest.getInstance("MD5");

byte[]digest=md.digest("Hello World".getBytes());


与报文摘要类似的机制是消息验证码(Message Authentication Code, MAC)。与报文摘要的不同在于消息验证码在计算过程中使用了密钥,只有掌握了密钥的接收者才能验证数据的完整性。消息验证码可以解决摘要本身也可能被篡改的问题。在实现中使用了散列函数的消息验证码被称为HMAC。一般的做法是对数据本身使用HMAC计算出消息验证码,再把消息验证码附加在原始数据之后,最后使用密钥对整个数据进行加密之后进行传输。消息验证码使用javax.crypto.Mac类进行计算。代码清单13-19中给出了计算消息验证码的示例。

代码清单13-19 计算消息验证码的示例


KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD5");

SecretKey key=keyGenerator.generateKey();

Mac mac=Mac.getInstance("HmacMD5");

mac.init(key);

byte[]result=mac.doFinal("Hello World".getBytes());