MD5 - Java加密与安全

MD5 - Java加密与安全_第1张图片

JAVA的MD5

MD5是一种摘要算法,他又称哈希算法,数字指纹

1. 摘要算法目的是计算任意长度数据的摘要

2. 而它的输出,也就是他的摘要,是一个固定的长度,相同的数据我们始终得到相同的输出

3. 而不同的输入数据我们会尽量得到不同的输出


摘要算法的目的就是为了验证原始数据是否被篡改

MD5 - Java加密与安全_第2张图片

如果我们的输入是任意长度的数据,比如一个byte数组,我们输出是一个固定长度的byte数组,我们就可以

把它称之为摘要算法,例如我们对hello字符串做一个摘要,如果他读到的是0x5e9182这个数,我们对hello,java

这个字符串做一个摘要算法,那么他就会得到一个不同的摘要输出,我们对hello,bob做一个摘要输出,

他就会得到一个不同的摘要输出

MD5 - Java加密与安全_第3张图片

Java的Object.hashCode方法就是一个摘要算法,他的输入是一个任意的数据,而他的输出是一个任意长度的数据

实际上它是一个int类型,4个长度的byte类型数组,相同的输入必须要得到相同的输出,这也是为什么我们复写

equals方法的时候,我们必须正确的复写hashCode方法

MD5 - Java加密与安全_第4张图片

我们再来看一下什么是碰撞?

碰撞是指两个不同的输入得到相同的输出,例如我们对abc和xyz都做哈希算法,我们可能会得到相同的输出,

这个时候我们就说发生了碰撞,碰撞能不能避免呢,碰撞是不能避免的,这是因为输出的字节长度是固定的,

而输入的长度是不固定的,所以哈希算法就是把一个无限的输入集合,到一个有限的输出集合,16个0到16个1

一共只有65536个输出,我们把无限的输入到65536个输出,那么肯定会有不同的输出到相同的输出的情况,

也就是碰撞

MD5 - Java加密与安全_第5张图片

我们再来看一下哈希算法的安全性:

1. 首先一个好的哈希算法碰撞率要低

2. 我们不能够猜测输出,我们来对比右边的两种哈希算法,如果java001的哈希算法是123456,而java002的哈希算法是123457

那么我们就可以推算出java003的哈希算法是123458,这样的哈希算法是不安全的哈希算法,一个安全的哈希算法对于任意的

会造成输出的完全不同,因此安全的哈希算法很难从结果找出思路,只能通过暴力穷举

MD5 - Java加密与安全_第6张图片

我们再来看一下常见的摘要算法:

1.有MD5,SHA-1,SHA-256,RipeMD-160,他们的输出长度是128bits,160bits,256bits,160bits,对应到字节数,MD5是16个字节,

SHA-1是20个字节,SHA-256是32个字节,RipeMD-160也是20个字节

MD5 - Java加密与安全_第7张图片

在JAVA中使用MD5非常的简单,首先我们导入java.security.MessageDigest这个类,然后我们通过MessageDigest的方法,

传入MD5获取MessageDigest这个类,然后我们反复调用update方法,最后我们用digest()方法,获得16个字节长度的byte数组,

这个byte数组就是我们输入数据的最后输出

 

MD5 - Java加密与安全_第8张图片

输入的数据是可以分片输入的,我们可以一次性输入helloworld,也可以把helloworld两个单词拆开,分别做update,

得到的结果是一样的

MD5 - Java加密与安全_第9张图片

MD5可以用来验证文件的完整性,我们在网上下载文件的时候,例如我们在MYSQL的网站下载MYSQL Community Server,

MYSQL的网站会给出一个MD5值,我们下载完文件以后,通过计算MD5,和网站给出的MD5对比,就可以知道在下载的过程中,

文件有没有被损坏

MD5 - Java加密与安全_第10张图片


MD5还可以存储用户的口令,如果我们有一个数据表,存放了username和password,我们的系统不存储原始口令,

而是存储原始口令的MD5,这样我们就不会在数据库中以明文的方式存储口令,那我们如何判断用户的口令是否正确呢

系统计算用户原始口令的MD5,并且与数据库存储的MD5对比,如果相同,说明口令正确,如果不同就说明口令错误

MD5 - Java加密与安全_第11张图片

MD5 - Java加密与安全_第12张图片

MD5 - Java加密与安全_第13张图片

MD5 - Java加密与安全_第14张图片

用MD5注意要避免彩虹表攻击,什么是彩虹表呢,彩虹表是预先计算好的,常用口令和MD5对照表,如果用户使用了常用口令,

那么黑客可以通过彩虹表,进行MD5就可以查出用户的原始口令,例如Bob,Alice,tim,我们存储的是MD5,但是黑客通过

彩虹表可以轻松的反查MD5的原始口令,分别是hello123,12345678,passwd0rd这样简单的原始口令,所以要抵御彩虹表的

攻击,我们不能直接原始口令的MD5,而是要对这个口令随机增加一个随机数,这个随机数通常称为salt,经过salt和原始口令

一块计算的MD5,就很难通过MD5再反查出来了
package com.learn.securl;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 我们先看一下如何使用MD5
 * @author Leon.Sun
 *
 */
public class MD5Demo {
	
	public static byte[] toMD5(byte[] input) {
		MessageDigest md = null;
		
		try {
			/**
			 * 传入字符串MD5
			 * 获得一个MessageDigest的实例
			 */
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		/**
		 * 紧接着传入输入的byte
		 */
		md.update(input);
		/**
		 * 最后我们用digest方法返回MD5
		 */
		return md.digest();
	}
	
	/**
	 * 然后我们使用一个main方法来使用MD5
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		/**
		 * 这里我们定义了一个字符串s
		 */
		String s = "MD5摘要算法测试";
		/**
		 * 通过getBytes把做一个字符串变成一个字节数组
		 * 注意MD5的输入是字节而不是字符串
		 * 所以我们把一个字符串变成一个字节数组
		 */
		byte[] r = toMD5(s.getBytes("UTF-8"));
		/**
		 * 最后我们要打印一个byte数组
		 * 如果我们直接打印byte数组
		 * 得到的是一个byte数组的地址
		 * 我们可以通过String.format传一个百分号032x
		 * 然后把一个byte数组变成一个BigInteger,
		 * 就可以使用16进制的形式打印数组
		 * c038cfbd1a587fcf4cbfe7d5a9094dca
		 * 我们看到MD5最后的结果是这样16进制表示的字节数组
		 * 
		 */
		System.out.println(String.format("%032x", new BigInteger(1,r)));
	}	
}
package com.learn.securl;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5SaltDemo {
	
	public static byte[] toMD5(byte[] input) {
		MessageDigest md = null;
		
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		md.update(input);
		return md.digest();
	}

	public static void main(String[] args) throws Exception {
		/**
		 * 假设我们的输入是我们用户的password
		 */
		String passwd = "helloworld";
		/**
		 * 同时我们为了增强我们MD5的安全性
		 * 我们引入了一个随机的Salt
		 */
		String salt = "Random salt";
		/**
		 * 然后把这两个字符串拼在一块
		 * 得到byte数组
		 * 然后再计算MD5
		 * 57de63c427b44d289128c3a8a496fb75
		 * 我们可以看到通过引入一个随机数salt,
		 * 我们可以把一个不安全的口令,
		 * 变为相对安全的MD5
		 * 
		 */
		byte[] r = MD5SaltDemo.toMD5((salt+passwd).getBytes("UTF-8"));
		System.out.println(String.format("%032x", new BigInteger(1,r)));
	}
	
}
最后我们总结一下:

1. MD5是一种常用的哈希算法,他的输出是固定长度的,128bits,也就是16个字节

2. MD5常用于验证数据的完整性

3. 当我们使用MD5存储口令的时候,要考虑到彩虹表的攻击

 

你可能感兴趣的:(MD5 - Java加密与安全)