MD(Message Digest ) 消息摘要算法之MD5

1、消息摘要的简介

     1.1消息摘要的概念

              唯一对应一个消息或文本的固定长度的值,由一个单向Hash加密函数对消息进行作用而产生。

     1.2 消息摘要的分类

            (1) MD (Message Digest)  消息摘要算法

            (2) SHA(Secure Hash Algorithm) 安全散列算法

            (3) MAC(Message Authentication Code) 消息认证码算法

     1.3  验证数据完整性(防止在传输中被篡改)

         MD(Message Digest ) 消息摘要算法之MD5_第1张图片   

2、MD算法系列

       2.1  MD算法的基本概念

              为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。

       2.2   MD算法的种类

               MD算法系列(JDK)

      MD(Message Digest ) 消息摘要算法之MD5_第2张图片

       2.3  MD 算法编程使用

          MD(Message Digest ) 消息摘要算法之MD5_第3张图片  

3、MD5(Message Digest Algorithm 5)简介

       MD5,全称为“Message Digest Algorithm 5”,中文名“消息摘要算法第五版”,它是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。严格来说,它是一种摘要算法,是确保信息完整性的。不过,在某种意义上来说,也可以算作一种加密算法。

MD5 算法具有很多特点:
  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  • 容易计算:从原数据计算出MD5值很容易。
  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  • 弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
  • 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。

      MD5 的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。
       MD5 其实在我们生活中是很常用的,似乎你并没有注意到,当你下载了一个镜像之后,你会发现下载页面还提供了一组 MD5 值,那么这组 MD5 值是用来做什么的呢?了解了 MD5 的作用之后,你就不难想到,MD5 是用来验证文件的一致性的,当你下载好镜像之后,你需要对该镜像做一次 MD5 的校验,得到的 MD5 值与下载页面提供的 MD5 值进行对比,以此来验证该镜像是否被篡改。
     MD5算法,可以用来保存用户的密码信息。为了更好的保存,可以在保存的过程中,加入盐。/在保存用户密码的时候,盐可以利用生成的随机数。可以将密码结合MD5加盐,生成的数据摘要和盐保存起来 。以便于下次用户验证使用。在用户表里面,也保存salt。
4、Java中MD5算法的实现
     4.1 MD5Utils.java
import java.io.File;
import java.io.FileInputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;

public class MD5Utils {
	/**
	 * 对数据,进行MD5算法的信息摘要计算
	 * 
	 * @param data
	 *            数据的字节数组
	 * @return
	 */
	public static String encryptMD5(byte[] data) {
		try {
			// 判断数据的合法性
			if (data == null) {
				throw new RuntimeException("数据不能为NULL");
			}
			// 获取MD5算法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			// 加入要获取摘要的数据
			md5.update(data);
			// 获取数据的信息摘要
			byte[] resultBytes = md5.digest();
			// 将字节数组转化为16进制
			String resultString = fromBytesToHex(resultBytes);
			return resultString;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	/**
	 * 对数据,进行MD5算法的信息摘要计算
	 * 
	 * @param data
	 *            要进行计算信息摘要的数据
	 * @return
	 */
	public static String encryptMD5(String data) {
		try {
			// 判断数据的合法性
			if (data == null) {
				throw new RuntimeException("数据不能为NULL");
			}
			// 获取MD5算法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			// 加入要获取摘要的数据
			md5.update(data.getBytes());
			// 获取数据的信息摘要
			byte[] resultBytes = md5.digest();
			// 将字节数组转化为16进制
			String resultString = fromBytesToHex(resultBytes);
			return resultString;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	/**
	 * 计算给定文件的信息摘要
	 * 
	 * @param path
	 *            文件的路径
	 * @return
	 * @throws Exception
	 */
	public static String getMD5OfFile(String path) {
		FileInputStream fis = null;
		DigestInputStream dis = null;
		String resultString = null;
		try {
			fis = new FileInputStream(new File(path));
			dis = new DigestInputStream(fis, MessageDigest.getInstance("MD5"));
			// 流输入
			byte[] buffer = new byte[1024];
			int read = dis.read(buffer, 0, 1024);
			while (read != -1) {
				read = dis.read(buffer, 0, 1024);
			}

			MessageDigest md = dis.getMessageDigest();
			byte[] resultBytes = md.digest();
			// 将字节数组转化为16进制
			resultString = fromBytesToHex(resultBytes);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			// 关闭流,释放资源
			CloseUtils.close(fis, dis);
		}
		return resultString;
	}

	/**
	 * 对数据,进行MD5算法的信息摘要计算,加入了salt
	 * 
	 * @param data
	 *            数据的字节数组
	 * @param salt
	 *            加入的盐
	 * @return
	 */
	public static String encryptMD5AndSalt(byte[] data, Object salt) {
		try {
			// 将data和盐拼接
			String datatemp = new String(data);
			String data_salt = mergeDataAndSalt(datatemp, salt);
			// 加入盐后,数据的信息摘要
			// 获取MD5算法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			// 加入要获取摘要的数据
			md5.update(data_salt.getBytes());
			// 获取数据的信息摘要
			byte[] resultBytes = md5.digest();
			// 将字节数组转化为16进制
			String resultString = fromBytesToHex(resultBytes);
			return resultString;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	/**
	 * 对数据,进行MD5算法的信息摘要计算,加入了salt
	 * 
	 * @param data
	 *            数据的字节数组
	 * @param salt
	 *            加入的盐
	 * @return
	 */
	public static String encryptMD5AndSalt(String data, Object salt) {
		try {
			// 完成数据和盐的拼接
			String data_salt = mergeDataAndSalt(data, salt);
			// 加入盐后,数据的信息摘要
			// 获取MD5算法
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			// 加入要获取摘要的数据
			md5.update(data_salt.getBytes());
			// 获取数据的信息摘要
			byte[] resultBytes = md5.digest();
			// 将字节数组转化为16进制
			String resultString = fromBytesToHex(resultBytes);
			return resultString;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	}

	/**
	 * 用于数据和salt的拼接
	 * 
	 * @param data
	 *            要计算数据摘要的数据
	 * @param salt
	 *            加入的盐
	 * @return
	 */
	private static String mergeDataAndSalt(String data, Object salt) {
		if (data == null) {
			data = "";
		}

		if ((salt == null) || "".equals(salt)) {
			return data;
		} else {
			return data + "{" + salt.toString() + "}";
		}

	}

	/**
	 * 
	 * @param encPass
	 *            加入盐后,计算的数据摘要
	 * @param rawPass
	 *            加盐前的数据
	 * @param salt
	 *            要加入的盐
	 * @return
	 */
	public static boolean isPasswordValid(String encPass, String rawPass,
			Object salt) {
		String data1 = encPass;
		String data2 = encryptMD5AndSalt(rawPass, salt);
		return data2.equals(data1);
	}

	/**
	 * 将给定的字节数组,转化为16进制数据
	 * 
	 * @param resultBytes
	 * @return
	 */
	private static String fromBytesToHex(byte[] resultBytes) {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < resultBytes.length; i++) {
			if (Integer.toHexString(0xFF & resultBytes[i]).length() == 1) {
				builder.append("0").append(
						Integer.toHexString(0xFF & resultBytes[i]));
			} else {
				builder.append(Integer.toHexString(0xFF & resultBytes[i]));
			}
		}
		return builder.toString();
	}
}
      4.2 CloseUtils.java
import java.io.Closeable;
import java.io.IOException;

public class CloseUtils {
	public static void close(Closeable... closeables) {
		for (int i = 0; i < closeables.length; i++) {
			if (closeables[i] != null) {
				try {
					closeables[i].close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
     4.3 测试代码
public class TestMD5 {

	// 在保存用户密码的时候,盐可以利用生成的随机数
	// 可以将密码使用,MD5加盐生成的数据摘要和盐保存起来
	// 以便于下次,用户验证使用

	// 待加密的明文
	public static final String DATA = "test";
	public static final String PATH = "mysql-installer-web-community-5.6.22.0.msi";
	public static final String SALT = "hello";

	public static void main(String[] args) {
		new TestMD5().testMD5AndSalt();
	}

	public void testMD5() {
		String aa = MD5Utils.encryptMD5(DATA);
		System.out.println(aa);
	}

	public void testMD5File() {
		String aa = MD5Utils.getMD5OfFile(PATH);
		System.out.println(aa);
	}

	public void testMD5AndSalt() {
		String data1 = MD5Utils.encryptMD5AndSalt(DATA, SALT);
		String data2 = MD5Utils.encryptMD5AndSalt(DATA.getBytes(), SALT);
		System.out.println(data1.equals(data2));
		System.out.println(MD5Utils.isPasswordValid(data1, DATA, SALT));
	}
}


你可能感兴趣的:(MD(Message Digest ) 消息摘要算法之MD5)