MD5算法解析

一. MD5概述
1. MD5介绍
MD5消息摘要算法,属Hash算法一类。
MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要(32位的数字字母混合码)。
2. MD5特点
- 不可逆
知道密文和加密方式,无法反向计算出原密码,但是有md5破解网站,专门查询MD5码
撞库:原理是:通过建立大型的数据库,把日常的各种句子通过md5加密成为密文,不断积累更新大量句子,放在庞大的数据库里;然后,有人拿了别人的密文,想查询真实的密码,就需要把密文拿到这个数据库的网站(免费MD5加密解密:https://md5.cn/)去查询。
- 长度固定
任意长度的数据,算出来的md5值长度都是固定的
- 强抗碰撞
想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
- 容易计算
原理通俗易懂
- 细微性(高度离散性)
对原数据进行任何改动,都会有很大的变化
二. 算法部分
1. 进行数据填充整理
(1) 基本知识
- 填充长度: 需要把数据填充到64字节 (512bit) 的倍数最少填充9个字节,最多填充(64+8)个字节
填充方式:
- 在原始数据的后面填充 0x80
- 填充N个0
- 使用小端序在最后面用8个字节填充原来的数据的bit长度
这里有一个小端序的概念,下面讲一下简单讲一下小端序和大端序
我们有两个字节:0x01020304
和0x05060708
我们要把这俩进行排序
可以看到小端序就是从数值的低位开始排,0x01020304
低位往高位依次是04 03 02 01,所以排的时候就是04030201
。0x05060708
同理,就是 08070605
,放一起就是 0403020108070605
大端序就是从高位开始排,就是我们所谓的正常排列顺序。这个简单。
我们回到填充的部分,我们举一个例子。
如图是一个41字节的数据,我们要对他进行填充。
41个字节对应的是(41 * 8)个bit,即328bit,我们要的是512bit,这个少184bit,即(184/8)个字节,即少23个字节。
(2) 填充过程
填充的过程如下:
(1)先在原始数据的后面填充 0x80
这样填了个80,原来少23个字节现在就少了22个字节。
(2)填0
那么填多少个0呢?填22-8即14个字节的0,因为我们要在最后留8个字节放别的东西
这样就填好了,现在还省最后的8个字节
(3)使用小端序在最后面用8个字节填充原来的数据的bit长度
然后我们使用小端序在最后面用8个字节填充原来的数据的bit长度,原来的是328bit,328=0x148,然后把这个0x148变成8个字节,就是在前面加0,变成0x0000000000000148。然后用小端序,即4810000000000000
这就是填充的最后结果,最后是64个字节,填充过程结束。
(3) 不填0的情况
那如果说,原文55个字节的话,我们应该填充9个字节,后面加80就剩了8个字节,之后咋办?这时候就不用填0了,直接加小端序8字节的原来数据就行了。
可以看到,没有填0的过程。
(4) 512bit不够的情况
那么,我们要是原文长度为56个字节呢?56个字节,我们如果填充为64个字节的话,那么还需要填充8个字节,80是必须加的,那么就剩了7个字节,不够用了。
我们刚才是填充为512个bit,我们512不够了,那就用512的倍数,这里用2倍即1024bit
原文56个字节,即448bit,还需要填576bit,即还需要填72字节,填80剩71个字节,然后填71-8个字节的0,然后剩的8个字节填小端排序的8字节原文数据。
2. MD5的执行流程
把填充后的数据按照64字节进行分组
假设有256个字节可分为4组,即一组64个字节
3. 计算过程
我们这里讲一下上图中的计算过程
(1) 四个初始化值
我们要准备四个固定的初始化值
- A: 0x67452301
- B: 0XEFCDAB89
- C: 0x98BADCFE
- D: 0x10325476
这四个值是固定的。
(2) 赋值
我们将 ABCD赋值给abcd
因为我们在计算的时候需反复的利用那四个值
(3) 计算与循环
计算过程的公式:
1 | a = ( (a + F + K[i] + M[g]) << s[i] ) + b |
这里的值啥意思下面会讲
然后就是交换数据:
1 | a = d |
这样abcd就被重新复制了,然后这个过程循环64次。
(4) 最后
当最后循环结束后,ABCD已经重新被赋值了好几次。
结果就是 A的小端序4字节 + B的小端序4字节 + C的小端序4字节 + D的小端序4字节
这就是最后16字节的结果
(5) 计算中的值
从 i = 0 循环到 i = 63 这个过程
I. 当 0 <= i <= 15
1 | F = (b & c) | ( (-b) & d) |
我们看一下M,比如这样
没四个字节一组
第0次循环,M[g] = 小端序的第1个4字节,即小端序的48656C6C
=6C6C6548
第1次循环,M[g] = 小端序的第2个2字节,即小端序的6F20576F
=6F57206F
同理一直到15次循环
II. 当 16 <= i <= 31
1 | F=(d & b) | ( (~d) & c) |
第16次循环,M[g] = 小端序的第 (5 * 16 + 1) % 16 个,即第1个4字节
第17次循环,M[g] = 小端序的第 (5 * 17 + 1) % 16 个,即第6个4字节
同理到31个
III. 当 32 <= i <= 47
1 | F=b^c^d |
IV. 当 48 <= i <= 63
1 | F=c^(b l (~d) |
V. K变量
K[i] =常量表的第i个
常量表如下:
这里一共64个常量
第一次循环,K[1] = 0xd76aa478
第二次循环,K[2] = 0xe8c7b756
……
VI. s变量
s[i]=位移表第i个
这个也是64个数据。
第一次循环,s[1] = 7
第二次循环,s[2] = 12
三. 代码实现
这里用python实现
1 | # 常量表 |