MD5加密算法与实现
文章目录
- MD5加密算法与实现
- MD5算法简介
- MD5算法的优势
- MD5算法流程
- 代码实现
MD5算法简介
MD5的全称是Message-Digest Algorithm,是Hash算法中的一种重要算法,具有单项加密、加密结果唯一、安全性能好等特点。MD5以512位分组来处理输入的信息,且每一分组又被划分为16个 32位子分组,经过了一系列的处理后 ,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
MD5算法的优势
(1)容易计算及不可逆性:
- 现在主流的编程语言基本都支持MD5算法的实现,所以非常容易计算出一个数据的MD5值。
- 而且MD5算法是不可逆的,也就是说我们无法通过常规的方式从MD5值倒推出它的原文。
(2)压缩性:
- 任意长度的数据,其MD5值都是一个32位长度的十六进制字符串,区分大小写(所以要和安卓、服务端商量好是用大写还是小写)。
(3)抗修改性:
- 对原数据做一丁点的改动,MD5值就会有巨大的变动。逆反过来理解一下这个特性,比如说两个原数据的MD5值非常相似,但是你不能想当然的认为它们俩对应的原数据也相似。这个特性表明的是,如果你想要很轻易的由MD5倒猜出原文数据是不可能的,因此这个特性在某种程度上表明了MD5算法是安全的。
(4)抗碰撞性:
抗碰撞性分为两种:
- 第一种,**知道了原数据及其MD5值,想要碰撞出这个MD5值,从而猜测出原数据,是非常困难的。**这种碰撞的难度表明的是,强制破解MD5算法是非常困难的,更别说上面的轻易倒推了。
- 第二种,我们知道MD5值总是一个32位的十六进制字符串,换算成二进制就是一个128位的字符串,因此所有的MD5值一共有2的128次方种可能性,**那么用自然界无穷的数据去对应这个有限的MD5值集合,会不会出现不同的数据有相同的MD5值呢?这样看来,理论上是会的,但是实际中想要找到两个不同的数据有着相同的MD5值是非常困难的。**这种碰撞的难度表明的是,我们可以放心的去使用MD5算法,不必担心不同的数据拥有相同的MD5值。
为什么说以上两种碰撞是困难的呢?因为要寻找这样一对碰撞是需要耗费非常非常长的时间的,依照现在计算机的计算能力,碰撞被认为在实际中是不可能发生的。因此,这个特性也在某种程度上表明了MD5算法的安全性。
MD5算法流程
- 信息填充首先需要对明文信息进行填充,使其位长度对512求余的结果等于448。因此,信息的位长度(Bits Length)将被扩展至 N512 + 448。然后,再在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理 ,现在的信息字节长度为 N512 + 448 + 64 = (N + 1) *512,即长度恰好是 512的整数倍。
- 结构初始化在处理过程中需要定义一个结构。该结构包含了每一次需要处理的一个明文块 (512bit)和计算出来的散列值 (128bit)。在散列的整个过程中,它的作用非常重要 ,各个明文块计算出来的散列值都是通过它来传递的。
- 分组文件将填充好的文件进行分组 ,每组 512位 ,共有N组。
- 处理分组使用算法处理每组数据。MD5算法在计算时会用到四个32位被称作链接变量 (Chaining Variable)的整数参数 ,在使用之前要对它们赋初值 ,分别就为 :A = 0x01234567,B = 0x89abcdef, C = 0xfedcba98,D =0x76543210。当设置好这四个链接变量后,就开始进入算法的四轮循环运算。循环的次数是信息中512位信息分组的数目。将上面四个链接变量复制到另外四个变量中 :A到 a,B到 b, C到 c,D到 d。主循环有四轮,每轮循环都很相似。第一轮进行16次操作。每次操作对 a、b、c和 d中的其中三个作一次非线性函数运算 ,然后将所得结果加上第四个变量,一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上 a、b、c或 d中之一,最后用该结果取代 a、b、c或 d中之一。
- 输出结果当全部信息处理完成后 ,将分组处理的结果进行处理,输出计算结果。所有这些完成之后 ,将 A、B、C、D分别加上 a、b、c、d。然后用下一分组数据继续运行算法 ,最后的输出是 A、B、C和 D的级联。当全部分组处理完成后,将结果级联 ,即得到了 MD5处理的结果。
代码实现
import java.math.BigInteger;
import java.security.MessageDigest;
/**
* 加密工具MD5类
*/
public class EncryptUtil {
public static String md5(String plainText){
String encryStr = null;
if (plainText != null && !"".equals(plainText)) {
try {
//md5实现类实例化
byte[] ret = MessageDigest.getInstance("md5").digest(plainText.getBytes());
//将获取的byte数组值转为16进制的字符串
String md5Code = new BigInteger(1, ret).toString(16);
//获取的字符串不足32位的用“0”补齐
for (int i = 0; i < 32 - md5Code.length(); i++) {
md5Code = "0" + md5Code;
}
encryStr = md5Code;
} catch (Exception e) {
e.printStackTrace();
}
}
return encryStr;
}
}
/*测试类*/
import org.junit.Test;
/**
* 测试输出:81dc9bd52d04dc20036dbd8313ed055
*/
public class TestEncrypt {
@Test
public void testMd5(){
System.out.println(EncryptUtil.md5("1234"));
}
}