消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。
消息摘要采用单向Hash函数将需加密的明文"摘要"成一串固定位数(如128bit)的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是“真身”的“指纹”了。
消息摘要具有不可逆性,在消息摘要生成过程中,会丢失很多原文的信息,而且无法找回。一个好的摘要算法,是极难产生Hash碰撞的,也就是找到另一段明文经计算后产生相同的摘要。
2.消息摘要算法-MD2、MD4、MD5MD是应用非常广泛的一个算法家族,尤其是 MD5(Message-Digest Algorithm 5,消息摘要算法版本5),它由MD2、MD3、MD4发展而来,由Ron Rivest(RSA公司)在1992年提出,目前被广泛应用于数据完整性校验、数据(消息)摘要、数据加密等。MD2、MD4、MD5 都产生16字节(128位)的校验值,一般用32位十六进制数表示。MD2的算法较慢但相对安全,MD4速度很快,但安全性下降,MD5比MD4更安全、速度更快。
目前在互联网上进行大文件传输时,都要得用MD5算法产生一个与文件匹配的、存储MD5值的文本文件(后缀名为 .md5或.md5sum),这样接收者在接收到文件后,就可以利用与 SFV 类似的方法来检查文件完整性,目前绝大多数大型软件公司或开源组织都是以这种方式来校验数据完整性,而且部分操作系统也使用此算法来对用户密码进行加密,另外,它也是目前计算机犯罪中数据取证的最常用算法。与MD5 相关的工具有很多,如 WinMD5等。
MD2和MD5已经由JDK提供了实现,MD4由Bouncy Castle实现。
在运行下面的所有Java程序之前,你需要引入Bouncy Castle和Commons Codec的依赖:
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15</artifactId> <version>1.46</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency>Java代码实现:
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Security; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.crypto.digests.MD4Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class MD5 { public static final String src = "md5 test"; public static void main(String[] args) throws NoSuchAlgorithmException { jdkMD5(); jdkMD2(); ccMD5(); ccMD2(); bcMD5(); bcMD4(); bc2jdkMD4(); } // 用jdk实现:MD5 public static void jdkMD5() throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] md5Bytes = md.digest(src.getBytes()); System.out.println("JDK MD5:" + bytesToHexString(md5Bytes)); } // 用jdk实现:MD2 public static void jdkMD2() throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD2"); byte[] md2Bytes = md.digest(src.getBytes()); System.out.println("JDK MD2:" + bytesToHexString(md2Bytes)); } // 用bouncy castle实现:MD5 public static void bcMD5() { MD5Digest digest = new MD5Digest(); digest.update(src.getBytes(), 0, src.getBytes().length); byte[] md5Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md5Bytes, 0); System.out.println("bouncy castle MD5:" + bytesToHexString(md5Bytes)); } // 用bouncy castle实现:MD4 public static void bcMD4() { MD4Digest digest = new MD4Digest(); digest.update(src.getBytes(), 0, src.getBytes().length); byte[] md4Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md4Bytes, 0); System.out.println("bouncy castle MD4:" + bytesToHexString(md4Bytes)); } // 用bouncy castle与jdk结合实现:MD4 public static void bc2jdkMD4() throws NoSuchAlgorithmException { Security.addProvider(new BouncyCastleProvider()); MessageDigest md = MessageDigest.getInstance("MD4"); byte[] md4Bytes = md.digest(src.getBytes()); System.out.println("bc and JDK MD4:" + bytesToHexString(md4Bytes)); } // 用common codes实现实现:MD5 public static void ccMD5() { System.out.println("common codes MD5:" + DigestUtils.md5Hex(src.getBytes())); } // 用common codes实现实现:MD2 public static void ccMD2() { System.out.println("common codes MD2:" + DigestUtils.md2Hex(src.getBytes())); } /** * byte[] 转 16进制 */ private static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } } 3.消息摘要算法-SHA