解疑释惑"/>
java生成文件md5十六进制串并和校验码比对以及md5算法的解疑释惑
网上下载文件的时候,常常看到会有各种校验值,比如我去现在apache,就可以看到下面的样子:
点击去之后可以得到一串密文“b8d8d49d8178734124c4ff6f3a409d3d”,这串密文的作用就是验证下载的文件是否安全,当下载的文件经过了修改之后得到的值就和官方网站公布的md5串不一致了,以此来校验下载的文件是否是安全且没有经过任何篡改的。
我现在就把这个文件下载下来了,放在了"d:\\zhao\\tmp\\apache-maven-3.5.2-bin.zip"这个位置,关键是我怎么计算自己下载的文件的md5串呢,当然,网上有很多工具的,可以自行百度下载。但是我还想自己一探究竟,起码要验证下自己的想法才肯罢休,于是乎就有了下面的java代码。
package com.zhao.fraud.test;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import org.junit.Test;
public class AppTest {@Testpublic void testFileMd5(){FileInputStream fis=null;try { MessageDigest md5 = MessageDigest.getInstance("MD5"); fis=new FileInputStream("d:\\zhao\\tmp\\apache-maven-3.5.2-bin.zip");byte[] buff = new byte[1024];int len=0;while((len=fis.read(buff))!=-1){md5.update(buff,0,len);}byte[] retBytes = md5.digest(); String md5str = parseByte2HexStr(retBytes); System.out.println(md5str);} catch (Exception e) { e.printStackTrace();} finally{if (fis!=null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}//把字节数组转成16进制字符串private String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); int length = buf.length;for (int i = 0; i < length; i++) { String hex = Integer.toHexString(buf[i]&0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); }
}
运行,得到结果:
因为我在parseByte2HexStr()函数中把十六进制字符串转为大写了,所以这里是大写,仔细比较一下我自己得到的值和网上公布的md5检验码可以发现是完全一致的。而当我把里面的文件随便修改一下,得到了一个“10CDBC4AD24C2B9F510882D66FA00CB9”,再修改,又变了,所以这就是自己写java程序和校验码比对的全部过程了。
既然用到了md5,就再详细说下md5。
什么是md5?
Message Digest Algorithm 5 简称md5,即消息摘要算法第五版。
java里面的md5算法最终应该返回什么?
md5我们又叫做md5字符串,自然是返回字符串了,java里面通过MessageDigest对象来计算md5的值,返回字节数组byte[]。字节数组怎么转为字符串呢,我们知道每个字节(byte)在java里面占有8位(bit),可以分成两个4位来看,因为一个4位最大也就是“1111”,所以一个字节正好可以用两个十六进制的字符来表示,比如"1111"就可以转变为十六进制的"f”。所以,结论就是,java里面的md5算法最终应该返回十六进制的字符串,这不是强制的,却是很好的解决办法。这也是为什么我们学md5就写md5吗,为什么总是还要牵涉到字节数组怎么转化为十六进制字符串的原因。
java里面的md5算法最终应该返回的十六进制字符串的长度?
不管用md5加密什么,一个2G的文件也好,一个“a”也罢,java里面最终返回的都是字节数组byte[],而且这个字节数组byte[]的长度总是16,也就是返回值总是占有128位,按照每4位可以转为一个十六进制的字符串的规则,这128位(bit)对应着32个十六进制的字符,好,一般而言,这经过字节数组byte[]转换而来的32个十六进制字符就是我们要返回的东西了。为什么说一般而言,因为有时候你还会见到只有8个十六进制字符的md5串,你要知道它只是把上面得到的32个十六进制字符截取了一下罢了。
怎么把字节数组byte[]转为十六进制字符串?
这个方法有很多,所以你可能看到网上如果搜素java里面的md5算法的时候,有可能看到这一篇是如此写,那一篇却又换了一个写法,你心里可能会犯嘀咕,是不是有一个不对啊,还很有可能为此而不知如何抉择,一头雾水的情况下索性不看了。这里要告诉你,方法自己很多种,只要能转换成功就可以。
说了这么多,该怎么写呢?干货来了:
package com.lzzcms.utils;
import java.security.MessageDigest;
public class CryptoUtilTest {public static String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); int length = buf.length;for (int i = 0; i < length; i++) { //toHexString参数时十进制的整数,与十六进制0xFF做与运算,是为了//确保真正存储的补码一致String hex = Integer.toHexString(buf[i]&0xFF); if (hex.length() == 1) { //如toHexString(15),就返回一个“f”,这里为了确保每个byte都能转为两个十六进制字符hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } public static String getMD5(String content) { String md5str = ""; try { // 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象 MessageDigest md = MessageDigest.getInstance("MD5"); // 2 得到要加密内容的byte数组 byte[] contentBytes = content.getBytes(); /* 3 计算后获得字节数组,返回值总是128个bit,即16个byte当要处理的内容contentBytes可以一次性获得的时候,可以用md.digest(contentBytes)来代替md.update(contentBytes);byte[] buff = md.digest()*/byte[] buff = md.digest(contentBytes); //相当于上面的md.digest(contentBytes)
// md.update(contentBytes);
// byte[] buff = md.digest(); System.out.println(buff.length);//16个字节System.out.println(new String(buff));//乱码// 4 把数组buff中每一字节(一个字节占八位)换成16进制字符最终连成md5字符串 md5str = parseByte2HexStr(buff); } catch (Exception e) { e.printStackTrace();} return md5str; } public static void main(String[] args) throws Exception {String md5 = getMD5("abcd_zhao");System.out.println(md5);}
}
运行结果:
16
+��/C�~Z�~���R�
2B19939D2F43F57E5AF57EF7ECC252E1
注意点:
1.需要注意的地方我已经写在了注释里,注意看注释
2.上边是加密一个短的字符串,关于加密相当长的字符串或者加密一个文件时可以分多次加密,调用MessageDigest对象的update方法即可,需要的时候可以使用update的重载方法update(input, offset, len);
当要处理的内容contentBytes可以一次性获得的时候,也可以用md.digest(contentBytes)来代替md.update(contentBytes);byte[] buff = md.digest()。
3.digest()方法是MessageDigest对象最终对内容进行md5加密的函数,而update方法是用于获取要加密的内容。
更多推荐
java生成文件md5十六进制串并和校验码比对以及md5算法的解疑释惑
发布评论