一、算法原理概述
MD5 即Message-Digest Algorithm 5 (信息-摘要算法5)
- MD4 (1990)、MD5(1992, RFC 1321) 由
Ron Rivest发明,是广泛 使用的Hash 算法,用于确保信息传输的完整性和一致性。 - MD5 使用little-endian(小端模式),输入任意不定长度信息,以 512-bit 进行分组,生成四个32-bit 数据,最后联合输出固定 128-bit 的信息摘要。
- MD5 算法的基本过程为:填充、分块、缓冲区初始化、循环压 缩、得出结果。
MD5 不是足够安全的。
基本流程


填充padding
- 在长度为Kbits 的原始消息数据尾部填充长度为Pbits 的标识 100…0,1< P < 512 (即至少要填充1个bit),使得填充后的消息位 数为:K + P=448 (mod 512).
- 注意到当K=448 (mod 512) 时,需要P= 512.
- 再向上述填充好的消息尾部附加K 值的低64位(即K mod 264), 最后得到一个长度位数为K + P+ 64= 0 (mod 512) 的消息。
分块
- 把填充后的消息结果分割为L个512-bit 分组:Y0, Y1, …, YL-1。
- 分组结果也可表示成N个32-bit 字M0, M1, …, MN-1,N= Lx16。
初始化
- 初始化一个128-bit 的MD 缓冲区,记为CVq,表示成4个32-bit 寄存器(A, B, C,D);CV0= IV。迭代在MD 缓冲区进行,最后一 步的128-bit 输出即为算法结果。
压缩函数

每轮循环中的一次迭代运算逻辑
对A迭代:a <— b+ ((a+ g(b, c, d) + X[k] + T[i]) <<<s)
缓冲区(A, B, C, D) 作循环轮换: (B, C, D, A) <—(A, B, C, D)
说明:
- a, b, c, d: MD 缓冲区(A, B, C, D) 的当前值。
- g: 轮函数(F, G, H, I中的一个)。
- <<<s: 将32位输入循环左移(CLS) s位。
- X[k] : 当前处理消息分组的第k个(k= 0..15) 32位字,即 M(qx16+k)。
- T[i] : T表的第i个元素,32位字;T表总共有64个元素,也 称为加法常数。
- : 模232 加法。
二、总体结构
1 | public class MD5 { |
三、模块分解
填充
填充时有两种情况
- 如果去掉整数个512bit的小组,剩下的位数不超过448bit,那样就可以先填充100…00(如果正好是448bit就不用填充了),再填充用K值的低64位64bit,那样的话就只是新增了一个小组
- 如果去掉整数个512bit的小组,剩下的位数超过了448bit,那样不够填充64bit,所以需要填充100..00到512bit,构成一个小组;然后再在第二个小组填充448bit个0,最后填充K值的低64位bit,这样就会新增两个小组
1 | //填充 |
分块
这里调用了divide分组函数,将完整小组分成个数为16,单个元素为32bit的数组
再直接调用H压缩函数,进行四轮循环和16次迭代
1 | //分块 |
分组函数
这个函数传入的参数是一个字节数组,以及一个代表从哪里开始截取的int值
效果就是将这个字节数组从start开始的64个字节组成一个
元素个数为16,单个元素为32bit的数组
采用的方法是每次取四个字节,采用小端的方式拼接成一个long型的整数
因为int在某些情况下是4个字节,所以就是正好32bit,但是带符号,就影响后面数据的运算
1 | //从inputBytes的index开始取512位,作为新的512bit的分组 |
MD5压缩函数
用了两层循环
第一层表示四轮循环
第二层表示16轮迭代
中间按照缓冲区运算的要求处理数据
这里直接处理的是result数组,也就是真实的缓冲区,所以在开始暂存了它们当时的值为a,b,c,d
运算完毕后要加上这些值
运算过程中以及运算结束会有一些防溢出的操作
(有时候没有这个就会出错)
1 | // groups[] 中每一个分组512位(64字节) |
最后结果转换为字符串
之前得到的结果就是result数组,四个元素,每个元素是一个32bit的数据
现在要把他们转换为字符串
但是需要小端的处理方式
即long的低位作为字符串的高位
每次以一个字节处理,32bit四个字节分别通过与运算和移位运算分离出来,再让long的低位在前,高位在后,得到十六进制字符串就是MD5编码的结果
1 | //将Hash值转换成十六进制的字符串 |
四、数据结构
long []groups 存储小组
String resultMessage存储结果字符串
//四个寄存器的初始向量IV,采用小端存储static final long A=0x67452301Lstatic final long B=0xefcdab89Lstatic final long C=0x98badcfeL
static final long D=0x10325476L
private long [] result={A,B,C,D}; 模拟存储结果的四个寄存器
static final long T[][]迭代过程中采用的近似值int(2^32 x |sin(i)|)
static final int k[][] 表示X[k]中的的k取值,决定如何使用消息分组中的字
static final int S[][] 各次迭代中采用的做循环移位的s值
private static long g(int i, long b, long c, long d) 4轮循环中使用的生成函数(轮函数)g
五、运行结果
输入原始消息:helloMD5
得到编码结果为:3ED9E5F6855DBCDBCD95AC6C4FE0C0A5
用站长之家的工具验证,结果正确
六、源代码
1 | public class MD5 { |
七、参考资料
MD5算法原理
DES算法实现

