MD5 - 加密算法简要介绍与JAVA实现

【1】MD5是什么

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。MD5是不可逆的。

该算法的文件号为:

RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)

MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。

对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

128位散列值转换为16进制字符串为32个字符。即,加密后的结果为32位16进制的字符串。

经典的哈希(散列)算法还有:MD2、MD4 和 SHA-1(目的是将任意长输入通过算法变为固定长输出,且保证输入变化一点输出都不同,且不能反向解密)。


【2】MD5的特点

① 长度固定

不管多长的字符串,加密后长度都是一样长,方便平时信息的统计和管理。

② 容易计算

从原数据计算出MD5值很容易。

③ 抗修改性

对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

④ 强抗碰撞

已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的(并非不可以)。


【3】MD5加密过程

第一种,加密字符串

① 获取信息摘要对象:md5

通过信息摘要单例的构造函数获取:

MessageDigest md5 = MessageDigest.getInstance("MD5");

② 获取摘要字节数组

两种方式:

byte[] bytes = str.getBytes();
byte[] digest = md5.digest(bytes);

或

byte[] bytes = str.getBytes();
md5.update(bytes);
byte[] digest = md5.digest();

③ 把摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5值.


第二种,加密文件

方法传入的是文件对象 : file

① 因为是文件不是方法,所以不是像刚才那样通过摘要获取字符串。

② 使用到另一个方法即可:就是信息摘要对象更新:md5.update(byte[] input)方法,用法是通过读取流,不断的更新从流中读到的"信息数组"。

③ 然后通过”信息摘要对象”获取摘要,不用参数:md5.digest(),此时返回的数组就已经是包含内容的摘要数组了。

④ 把摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5值。

同样来源除了文件还可以是url,过程同上。


【4】MD5工具类

package com.web.encrypt;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MD5Util {
	// 用来将字节转换成 16 进制表示的字符
	private static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd','e', 'f' };
	protected static MessageDigest messagedigest = null;
	
	static {
		try {
			messagedigest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException nsaex) {
			System.err.println(MD5Util.class.getName()
					+ "初始化失败,MessageDigest不支持MD5Util。");
			nsaex.printStackTrace();
		}
	}
	
	// 加密字符串
	public static String getMD5(String str){
		
		byte[] bs = str.getBytes();
		
		return getMD5FromByte(bs);
	}
	
	private static String getMD5FromByte(byte[] source) {
		String s = null;
		
		try {
			java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
			md.update(source);
			byte tmp[] = messagedigest.digest();
			// MD5 的计算结果是一个 128 位的长整数(16个字节),转为16进制则为32个字符
			char str[] = new char[16 * 2]; 
	// 每个字节用 16 进制表示的话,使用两个字符(一个8位->2个4位->2个16进制字符),所以表示成 16 进制需要 32 个字符
			int k = 0; // 表示转换结果中对应的字符位置
			for (int i = 0; i < 16; i++) { 
				// 从第一个字节开始,对 MD5 的每一个字节
				// 转换成 16 进制字符的转换
				byte byte0 = tmp[i]; // 取第 i 个字节
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				 // 取字节中高 4 位的数字转换,>>>为逻辑右移,将符号位一起右移
				str[k++] = hexDigits[byte0 & 0xf];
				 // 取字节中低 4 位的数字转换
			}
			s = new String(str); 
			// 换后的结果转换为字符串

		} catch (Exception e) {
			e.printStackTrace();
		}
		return s;
	}
	
	// 加密文件对象
	public static String getFileMD5String(File file) throws FileNotFoundException {  
		String value = null;  
		FileInputStream in = new FileInputStream(file);  
		try {  
			MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());  
			MessageDigest md5 = MessageDigest.getInstance("MD5");  
			md5.update(byteBuffer);  
			BigInteger bi = new BigInteger(1, md5.digest());  
			value = bi.toString(16);  
		} catch (Exception e) {  
			e.printStackTrace();  
		} finally {  
			if(null != in) {  
				try {  
					in.close();  
				} catch (IOException e) {  
					e.printStackTrace();  
				}  
			}  
		}  
		return value;  
	}  
	
	//参数为文件路径
	public static String getFileMD5String(String  filePath) throws FileNotFoundException {  
	        String value = null;  
	        File file=new File(filePath);
	        FileInputStream in = new FileInputStream(file);  
	    try {  
	        MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());  
	        MessageDigest md5 = MessageDigest.getInstance("MD5");  
	        md5.update(byteBuffer);  
	        BigInteger bi = new BigInteger(1, md5.digest());  
	        value = bi.toString(16);  
	    } catch (Exception e) {  
	        e.printStackTrace();  
	    } finally {  
	            if(null != in) {  
	                try {  
	                in.close();  
	            } catch (IOException e) {  
	                e.printStackTrace();  
	            }  
	        }  
	    }  
	       return value;  
	    }  
	    
	//参数为url
	public static String getFileMD5StringByURL(String urlString) throws IOException {		

		URL url = new URL(urlString);
		
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		
		BufferedInputStream fis = null;
		
		fis = new BufferedInputStream(connection.getInputStream());
		
		byte[] buffer = new byte[1024];
		int numRead = 0;
		while ((numRead = fis.read(buffer)) > 0) {
			
			messagedigest.update(buffer, 0, numRead);
		}
		fis.close();
		return bufferToHex(messagedigest.digest());
	}
	
	//参数为字节数组
	public static String getMD5String(byte[] bytes) {
		messagedigest.update(bytes);
		return bufferToHex(messagedigest.digest());
	}
	
	// 将字节数组转换为16进制的字符串
	private static String bufferToHex(byte bytes[]) {
		int m = 0;
		int n = bytes.length;
		StringBuffer stringbuffer = new StringBuffer(2 * n);
		int k = m + n;
		for (int l = m; l < k; l++) {
			appendHexPair(bytes[l], stringbuffer);
		}
		return stringbuffer.toString();
	}

	private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
		char c0 = hexDigits[(bt & 0xf0) >> 4];
		// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移
		char c1 = hexDigits[bt & 0xf];
		// 取字节中低 4 位的数字转换 
		stringbuffer.append(c0);
		stringbuffer.append(c1);
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值