前言
最近看了很多关于消息摘要算法这方面的资料,既有CSDN上面各路大神写的文章,也有这些算法的标准文档。有的讲的比较啰嗦,有的给出来的代码是直接调库的。我想写一篇文章,帮助自己理清思路,利用图解简明扼要地说清目前最流行的MD5算法的原理。
MD5算法概述
MD5信息摘要算法(MD5 Message-Digest Algorithm)是一种被广泛使用的密码散列函数,由MD4改进而来。点我看MD4算法原理。
MD5本质上是一个哈希函数。但是MD5具有雪崩效应(Avalanche Effect)、抗碰撞性等的性质。为了保证这些性质,MD5的算法设计比较复杂。下面就来说明MD5算法的原理。
MD5算法的处理步骤可以概括为三步:数据填充、分组循环变换、拼接输出。
数据填充
MD5算法的第二步“分组循环变换”是以512位为一个分组进行处理的。因此,需要把数据填充成长度为512位的倍数。具体填充步骤如下:
1、先填充一个“1”,后面加上k个“0”。其中k是满足(n+1+k) mod 512 = 448的最小正整数。
2、追加64位的数据长度(bit为单位,小端序存放)
填充完的数据大概长这样:
![67092863f9ce6013810ff46d62720e89.png](https://img-blog.csdnimg.cn/img_convert/67092863f9ce6013810ff46d62720e89.png)
分组循环变换
先初始化A、B、C、D四个32位常数,然后将填充完成后的数据划分成一个个512位的分组,依次进入循环变换。A、B、C、D也参与到循环变换中。数据分组进去变换的时候,大概走这么个流程:
![0cd088a83e4ec29c9020987792f0624b.png](https://img-blog.csdnimg.cn/img_convert/0cd088a83e4ec29c9020987792f0624b.png)
循环变换是整个MD5算法最核心,也是最复杂的部分。一个512位分组的数据被进一步划分为16个32位的子分组,对每个子分组进行下图所示的变换:
![e246580a4c7eb7ce577f4b13d92d507c.png](https://img-blog.csdnimg.cn/img_convert/e246580a4c7eb7ce577f4b13d92d507c.png)
上面只是画出了一个子分组进行的变换。下面对图中的元素进行说明:
- 图中的F函数代表一次由位运算构成的非线性变换,每一轮循环变换用到的F函数不一样。
- 加号表示加法运算。
- 常数AC的值在每一次变换中都不一样,表达式为
,i表示第i次变换。
- 左移位数S有规律地周期性变化。
数据的16个子分组都参与到上图所示的变换,顺序不定。当16个子分组处理完成时,我们就说完成了一轮循环变换。MD5的一个数据分组一共需要进行四轮的循环变换。将四轮循环变换后得到的A、B、C、D的值分别和原来的值相加,就是A、B、C、D进行循环变换后的结果。
拼接输出
这里用一句话概括:将经过若干次循环变换后的A、B、C、D以十六进制的形式拼接起来,就是传说中的MD5码了。
C语言实现
以下代码根据参考文献修改、注释而来,毕竟MD5算法不是我原创的。
/*
参考文献
[1] Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321, MIT and RSA Data Security, Inc., April 1992.