java生成文件md5十六进制串并和校验码比对以及md5算法的解疑释惑

网上下载文件的时候,常常看到会有各种校验值,比如我去现在apache,就可以看到下面的样子:

image.png

点击去之后可以得到一串密文“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 {
	@Test
  public 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();  
	    } 
}

运行,得到结果:

image.png

因为我在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方法是用于获取要加密的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值