Java计算文件MD5值

在文件上传下载相关的操作中,我们通常会遇到需要计算文件MD5的场景,计算文件MD5值的方法和计算字符串的MD5值有些类似,这里先来介绍普通的计算字符串的MD5方法。

commons-codec这个jar给我们提供了一个MD5实现,普通的MD5实现,基本大同小异,最终的结果也相同,这里不能说的太过,为什么称为普通的MD5,因为实现思路是一样的,而且只要是相同的字符串,计算的结果也一样,因此也很容易被破解,虽然MD5这个算法本身是不可逆的,但是根据彩虹表的破解方式,或者在线破解,一些常用的密码很容易被猜到。

先来看看commons-codec提供的MD5的实现:

DigestUtils.md5Hex(String source);

就这么一行简单的代码就帮我们实现了MD5算法。

也有很多不用commons-codec提供的api,借助java security api实现MD5算法的,这里给出一个简单的示例:

private static final String[] strHex=
{"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
private static MessageDigest digest = null;

static{
	try {
		digest = MessageDigest.getInstance("MD5");
	} catch (NoSuchAlgorithmException e) {
		e.printStackTrace();
	}
}
public static String getMD5(String source){
	try {
		byte[] data = source.getBytes("UTF-8");
		return buffer2Hex(digest.digest(data));
	} catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	}	
	return null;
}

public static String buffer2Hex(byte[] data){
	StringBuffer sb = new StringBuffer();
	for(int i=0;i

相信大家常见的MD5算法就是长这个样子的,其中,我们看到的复杂的部分就是在进行字节数组转十六进制。其实java提供的api已经帮助我们完成了MD5核心算法,我们这里进行的字节数组转16进制,其实是这个算法的冰山一角。

当然字节数组转16进制,也有很多办法,所以这个方法也有很多变种:

public static String buffer2Hex3(byte[] data){
        StringBuffer sb = new StringBuffer();
        for(int i=0;i             int d1 = data[i];
            if(d1<0){
                d1 = d1 & 0xff;
            }
            if(d1<16){
                sb.append("0");
            }
            sb.append(Integer.toHexString(d1));
        }
        return sb.toString();
}

借助BigInteger直接转16进制:    
public static String buffer2Hex4(byte[] data){
        BigInteger res = new BigInteger(1, data);
        return res.toString(16);

当然也有利用字符数组来替换前面的字符串数组的算法:

private static final char[] digestHex={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

public static String buffer2Hex2(byte[] data){
        StringBuffer sb = new StringBuffer();
        for(int i=0;i             byte d = data[i];
            char d1 = digestHex[(d & 0xf0) >> 4];
            char d2 = digestHex[d & 0xf];
            sb.append(d1);
            sb.append(d2);
        }
        return sb.toString();
}

我们知道,这些不同的实现,核心的算法是字节数组转十六进制。那么对于文件而言,如何计算MD5,我们可以试想,如果把文件转为字节数组了,是不是就可以套用这个后面字节数组转十六进制的方法了。事实上,确实如此,我们只需要将文件读入内存,然后将其转为字节数组,剩下的就是和求字符串的MD5方法一样了。

commons-io提供了FileUtils.readFileToByteArray(File file)这个api,得到的结果就是byte[]类型的字节数组。所以求文件的MD5算法就有了这样简单的实现了:

public static String md5Hex(File file) {
        try {
            return DigestUtils.md5Hex(FileUtils.readFileToByteArray(file));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
  }

如果你有兴趣,可以将FileUtils.readFileToByteArray(file)方法替换为自己编写的一个简单的实现:通过IO流的方式将文件读入内存,然后将其转为byte[]类型的数组。

常见的字符串经过MD5加密之后的结果:

  • 123456->e10adc3949ba59abbe56e057f20f883e
  • admin ->21232f297a57a5a743894a0e4a801fc3
  • 111111->96e79218965eb72c92a549dd5a330112
  • 666666->f379eaf3c831b04de153469d1bec345e 

我们通过MessageDigest.digest(byte[]) 得到的数组,无论原始字符串或者文件多大,得到的字节数组,长度都是16,因此根据10进制转为16进制,结果都是32位的。再次说明了,普通的MD5算法还是有可能被破解的。

你可能感兴趣的:(java,md5,file)