md5的简单实现
XZAN
后台工程师
好久没写blog,最近也正好想实现一下常见的摘要算法。
md5的背景介绍
md5是一种消息摘要算法,它能够将输入的任何数据经过运算产生128 bit的hash值(这个hash便是这段消息的摘要) 一般情况下,md5产生的消息摘要发生碰撞得可能性很低(还是存在的),所以人们常用通过对比经md5运算后摘要 来验证一段消息的完整性
md5的算法
md5算法可以描述成下面5个步骤:
step 1.添加填充数据
首先我们要添加1位 1,接着填充n位(n 非负)0到原消息后面,使填充后的数据长度lens满足
lens mod 512=448 //计量单位是bit这样,我们添加的数据长度范围是 1 bit到 512 bit之间
step 2.添加数据长度
这一步,我们将原始数据的长度用一个64位(小端字节序表示)的整型表示,然后将这64位数据添加到填充之后的数据上 这里有几个注意点
- 这里的消息长度是原数据的长度 
- 当数据长度超过2的64次方时,只使用低64位的数据 
经过上面两个步骤,我们的数据长度变成了
lens=512*k+448+64
lens=512*(k+1)step 3 初始化数据
初始化4个32位的数据 A B C D
    word A: 01 23 45 67  // A = 0x67452301
	word B: 89 ab cd ef  // B = 0xefcdab89
	word C: fe dc ba 98  // C = 0x98badcfe
	word D: 76 54 32 10  // D = 0x10325476step 4 对消息进行分组运算
将消息分成512位一组,将这一组数据保存在长度为16的unsigned int的数组中,进行四轮的运算。
这里需要定义四种操作
F(x, y, z) (((x) & (y)) | ((~x) & (z)))
G(x, y, z) (((x) & (z)) | ((y) & (~z)))
H(x, y, z) ((x) ^ (y) ^ (z))
I(x, y, z) ((y) ^ ((x) | (~z)))分别用于四轮运算,其中表达式中的T是个64个元素的unsigned int 数组
其中T[i]是4294967296*abs(sin(i))的整数部分
我们用临时变量保存本组运算结果
AA=A
BB=B
CC=C
DD=D
//第一轮,我们用
[abcd k s i] 表示  a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s)
//执行下面的运算
[ABCD  0  7  1]  [DABC  1 12  2]  [CDAB  2 17  3]  [BCDA  3 22  4]
[ABCD  4  7  5]  [DABC  5 12  6]  [CDAB  6 17  7]  [BCDA  7 22  8]
[ABCD  8  7  9]  [DABC  9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]
[ABCD 12  7 13]  [DABC 13 12 14]  [CDAB 14 17 15]  [BCDA 15 22 16]
//第二轮,我们用
[abcd k s i] 表示  a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s)
//执行下面的运算
[ABCD  1  5 17]  [DABC  6  9 18]  [CDAB 11 14 19]  [BCDA  0 20 20]
[ABCD  5  5 21]  [DABC 10  9 22]  [CDAB 15 14 23]  [BCDA  4 20 24]	      
[ABCD  9  5 25]  [DABC 14  9 26]  [CDAB  3 14 27]  [BCDA  8 20 28]
[ABCD 13  5 29]  [DABC  2  9 30]  [CDAB  7 14 31]  [BCDA 12 20 32]
//第三轮,我们用
[abcd k s i] 表示  a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s)
[ABCD  5  4 33]  [DABC  8 11 34]  [CDAB 11 16 35]  [BCDA 14 23 36]
[ABCD  1  4 37]  [DABC  4 11 38]  [CDAB  7 16 39]  [BCDA 10 23 40]
[ABCD 13  4 41]  [DABC  0 11 42]  [CDAB  3 16 43]  [BCDA  6 23 44]
[ABCD  9  4 45]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA  2 23 48]
//第四轮,我们用
[abcd k s i] 表示  a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s)
//再执行下面的运算
[ABCD  0  6 49]  [DABC  7 10 50]  [CDAB 14 15 51]  [BCDA  5 21 52]
[ABCD 12  6 53]  [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA  1 21 56]
[ABCD  8  6 57]  [DABC 15 10 58]  [CDAB  6 15 59]  [BCDA 13 21 60]
[ABCD  4  6 61]  [DABC 11 10 62]  [CDAB  2 15 63]  [BCDA  9 21 64]最后对结果进行暂存,使得
A=A+AA
B=B+BB
C=C+CC
D=D+DDstep 结果输出
依次将A B C D中的数据输出。
最后要注意的一点是:在处理输入消息以及输出最终哈希值时,涉及到将多字节值转换为字节序列的操作(例如,初始化向量和最终哈希结果),应该使用小端字节序。而在内部计算过程中,即对32位整数执行逻辑运算和循环移位操作时,并不直接涉及字节序的问题。
主要参考资料
本文链接:/post/understanding-md5-algorithm-from-padding-to-hash-value-generation
分享声明
本文链接:/post/understanding-md5-algorithm-from-padding-to-hash-value-generation
许可协议:遵循 CC BY-SA 4.0 共享。转载或改编需署名作者 XZAN,并在相同许可下发布。