MD5信息摘要算法描述
前言
关于MD5算法的详细描述,可参考链接https://www.ietf.org/rfc/rfc1321.txt(英文文档),如链接失效,可访问本人所做的备份https://blog.csdn.net/weixin_44567318/article/details/113060080
术语和约定
在本文档中,字是32位(32-bit)的,字节是8位(8-bit)的。
比特(bit)序列可以以一种自然的方式解释为字节(byte)序列,其中每连续的8位比特被解释为一个字节,每个字节的高阶位列在前面(最高有效位在前,MSB
)。
类似地,字节序列可以被解释为32位字(word)序列,其中每连续的4个字节都被解释为一个字,每个字的低阶字节在前(最低有效字节在前,即小端模式
)。
用 x_i 表示“ x 下标 i ”。如果下标是一个表达式,则用大括号将其括起来,如 x_{i+1} 所示。
类似地,我们用∧表示乘方,所以 x^i 表示 x 的 i 次方。
用符号“+”表示字(word)的相加(即模2^32加法,不考虑进位溢出)。
用 X <<< s 表示将 X 循环左移 s 位得到的32位值。
用 not(X) 表示 X 的按位取反。
用 X v Y 表示 X 和 Y 的按位或。
用 X xor Y 表示 X 和 Y 的按位异或。
用 XY 表示 X 和 Y 的按位与。
MD5算法描述
假设我们有b比特 (bit) 的信息作为输入,这里b是任意的非负整数(即b∈N),b可以是0,它不需要是8的倍数,它可以是任意大的(实际上当消息长度超过2^64比特时,长度(64位)将会发生溢出,数据将被截断处理
)。我们假设消息的比特写作如下:
执行以下五个步骤来计算消息的摘要。
步骤1——添加填充比特
对消息进行“填充”(扩展),以使它的长度(以比特为单位)对512取模(求余)后等于448。也就是说,对消息进行扩展,以使它的长度(扩展后)距离512位的倍数只差64位(剩下64位用于指明未填充前原数据的长度
)。
`填充总是执行的,即使消息的长度对512取模已经是等于448。
填充的过程如下:在消息后面追加一个“1”,然后再加上若干个“0”,以使它的长度(以比特为单位)对512取模(求余)后等于448。总之,至少填充1位,最多512位。
步骤2——附加长度
b的64位表示(填充比特前的原消息长度)被追加到上一步骤的结果中,在不太可能的情况下b大于264,那么只有b的低64位被使用(这些位以两个32位字和低字在前的方式被追加
)。
此时产生的结果消息(在填充比特和附加64位长度之后)的长度是512位的整数倍。也即是说,此消息的长度是16字的整数倍。让M[0…N-1]表示结果消息的字(word),其中N是结果消息的总字(32位)数, N是16的倍数。
步骤3——初始化MD缓冲
一个四字(word )缓冲区(A、B、C、D)用于计算消息摘要,这里A,B,C,D每个都是32位寄存器。这些寄存器初始化为以下十六进制值(低字节在前):
以A为例,如果采用小端存储模式(低字节存储在低地址),则0x01存储在地址处,0x67存储在高地址处。
步骤4——以16字的数据块为单位处理消息
我们首先定义四个辅助函数,每个函数的输入为三个32位字,输出为一个32位字。
在每个位中,F 表现为一个条件语句:如果X,那么Y,否则Z。函数 F 可以用 + 而不是 v 来定义,因为 XY 和 not(X)Z 不会在相同的位置上有1。
函数G,H,I和函数F很相似,它们以“逐位并行”的方式,从X,Y,Z 产生它们的输出。注意函数 H 是其输入的按位的“异或”或“奇偶”函数。
这一步使用了一个由sin函数构成的64元素的表T[1…64]。用 T[i] 表示表的第 i 个元素,其值为 4294967296 * abs(sin(i))
的整数部分,其中 i 的单位为弧度。
将步骤2中得到的 N 字(32位)的结果消息,每16字(共512 bit)划分为一个数据块,然后对数据块进行如下处理:
/* 处理每个16字数据块,共有(i=N/16)个 数据块 */
For i = 0 to N/16-1 do
/* 复制数据块i到 X(16元素的字数组),X为目标机器端格式(小端/大端) */
For j = 0 to 15 do
Set X[j] to M[i*16+j]. /*M为小端格式,复制到X时注意格式转换*/
end /* j上的循环 */
/* 将A保存为AA, B保存为BB, C保存为CC, 和D保存为DD */
AA = A
BB = B
CC = C
DD = D
/* 第一轮 */
/* 用 [abcd k s i] 表示操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
/* 执行以下16个操作 */
[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). */
/* 执行以下16个操作 */
[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). */
/* 执行以下16个操作 */
[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). */
/* 执行以下16个操作 */
[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 + DD
end /* i上的循环 */
步骤5——输出
作为输出产生的消息摘要是A、B、C、D。也就是说,从A的低字节开始,到D的高字节结束
这样就完成了对MD5的描述。