消息摘要算法又成散列算法,其核心在于散列函数的单向性。即通过散列函数可获得对应的散列值,但不可以通过散列值反推其原始信息。
消息摘要算法分为以下三大类:
MD(Message Digest ,消息摘要)
SHA(Secure Hash Algorithm ,安全散列算法)
MAC(Message Authentication Code ,消息认证码)
本篇文章仅说明MD5算法
MD系列算法包括MD2、MD4、MD5这三种算法
MD系统的消息摘要算法都产生128位的消息摘要,转换成16进制之后就是32位的16进制数。即16进制的MD5消息摘要都是32位的
Java自带的MessageDigest类(如果需要处理流的则使用DigestInputStream、DigestOutputStream)实现MD5摘要信息算法
注意:Java 自动的仅支持MD2和MD5
/**
* MD5消息摘要
* @throws Exception
*/
public static void md5Hex() throws Exception{
//获的MD5消息摘要
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update("中国".getBytes("utf-8"));
byte[] result = md5.digest();
//转换成16进制字符串,注意:转换成16进制不是MD5消息摘要中的步骤,所以它不是必须的
String hexString = toHexString(result);
System.out.println(hexString);
}
/**
* 将字节数组转换成16进制的字符串
* @param bytes
* @return
*/
public static String toHexString(byte[] bytes){
StringBuffer sb = new StringBuffer();
for(byte b: bytes){
String hex = Integer.toHexString(b & 0x0FF);
if(hex.length()==1) hex = "0" + hex;
sb.append(hex);
}
return sb.toString();
} |
通过Apache的消息摘要工具类org.apache.commons.codec.digest.DigestUtils实现
Apache的消息摘要工具类实际是对Java的MessageDigest类使用步骤的封装,简便了我们的开发
DigestUtils.md5Hex("中国".getBytes("utf-8"))
实现文件的MD5消息摘要计算
方案一、跟计算普通字符串的MD5值一样,使用MessageDigest类
public static void md5File2() throws Exception{
FileInputStream fis = new FileInputStream("f:\\T1-1_20140910_80070000.dat");
byte[]buffer = new byte[1024];
int count = -1;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
while((count=fis.read(buffer))>-1){
bout.write(buffer, 0, count);
}
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] result = md5.digest(bout.toByteArray());
//打印出十六进制字符串
System.out.println(toHexString(result));
}
方案二、使用DigestInputStream类
public static void md5File1() throws Exception{
DigestInputStream dis = new DigestInputStream(new FileInputStream("f:\\T1-1_20140910_80070000.dat") ,MessageDigest.getInstance("MD5"));
byte[]buffer = new byte[1024];
while(dis.read(buffer)>-1){
}
MessageDigest md5 = dis.getMessageDigest();
byte[] result = md5.digest();
System.out.println(toHexString(result));
}
通过DigestInputStream类的read方法可以知道,其实使用DigestInputStream类实现的原理跟“方案一”是一样的。
它也是从文件流中读取字节,然后调用MessageDigest类的update方法更新进去的。下面是DigestInputStream类的read方法
public int read(byte[] b, int off, int len) throws IOException {
int result = in.read(b, off, len);
if (on && result != -1) {
digest.update(b, off, result);
}
return result;
}