MD5消息摘要算法(Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值,用于确保信息传输完整一致。MD5有MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。MD5广泛使用在为文件传输提供一定的可靠性方面。例如:服务器预先提供一个MD5校验和,用户下载完文件之后,用MD5算法计算下载文件的MD5校验和,然后通过检查这两个检验和是否一致,就能判断下载的文件是否出错。
MD5算法处理不定长的输入信息,得到定长的128位输出。MD5将输入信息以512位进行分组,且每一分组又被划分为16个32位子分组,经过一系列处理之后算法的输出得到4个32位的输出,将此四个输出拼接起来就可以获得最终的加密结果。
下面介绍算法的主要步骤:
k
bits,如果二进制串长度k mod 512!=448
,则在该二进制串最后面补充p
bits的标识,100…0(一个1和多个0),1≤p≤512,使得填充后的消息位数满足: k + p ≡ 448 ( m o d 512 ) k+p ≡ 448(mod 512) k+p≡448(mod512)k
值二进制串表示的低64位(即 k m o d 2 64 k mod 2^{64} kmod264 ),由于MD5加密算法采用小端模式(little-endian),所以将此64位二进制串的最后一个字节放置在最前方,倒数第二个字节放置在第二个自接触,……,第一个字节放置在最后方,最终处理过后的信息长度为512的整数倍。L
个512-bit分组: Y 0 Y_0 Y0, Y 1 Y_1 Y1,…, Y L − 1 Y_{L-1} YL−1。然后再将每个分组继续划分为16个32-bit长的子分组 X 0 X_0 X0, X 1 X_1 X1,…, X 15 X_{15} X15 A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476
wordA | 01 | 23 | 45 | 67 |
---|---|---|---|---|
workB | 89 | AB | CD | EF |
wordC | FE | DC | BA | 09 |
wordD | 76 | 54 | 32 | 10 |
Little-Endian
将低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,相反Big-Endian将高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。存储结构与CPU体系结构和语言编译器有关。PowerPC系列采用Big Endian方式存储数据,而Intel x86系列则采用Little-Endian方式存储。
第四步:总控流程
以512-bit消息分组为单位,每一份组 Y q ( q = 0 , 1 , . . . L − 1 ) Y_q(q=0,1,...L-1) Yq(q=0,1,...L−1)经过四轮循环压缩算法,表示为:
C V 0 = I V CV_0 = IV CV0=IV
C V i = H M D 5 ( C V i − 1 , Y i ) CV_i = H_{MD5}(CV_{i-1}, Y_i) CVi=HMD5(CVi−1,Yi)
输出结果: M D = C V L MD = CV_L MD=CVL
第五步:MD5压缩函数 H M D 5 H_{MD5} HMD5
T
表示元素T[]
和和消息分组的不同部分X[]
做16次迭代运算,生成下一轮循环的输入。说明:
迭代运算如下:
dtemp := d
d = c
c = b
b = b + ((a+轮函数(b,c,d)+X[k]+T[i] <<< s))
a = dtemp
轮函数定义如下:
轮次 | Function g | g(b,c,d) |
---|---|---|
1 | F(b,c,d) | (b & c) | (~b & d) |
2 | G(b,c,d) | (b & d) | (c & ~d) |
3 | H[b,c,d) | (b ^ c ^ d) |
4 | I(b,c,d) | c ^ (b | ~d) |
a,b,c,d
:MD缓冲区(A,B,C,D)的当前值;
X[k]
:当前处理消息分组的16个子分组;
T[i]
:T表的第i个元素,32位字;T表总共有64个元素,也称为加法常数
<<
:将32位输入循环左移s位
+
: 模 2 32 2^{32} 232加法。
其中X[k]
具体如下:
4轮循环中,第i次迭代(i=0…63)使用的X[k]
的确定;
T
表定义如下:
T [ i ] = i n t ( 2 32 ∗ ∣ s i n ( i ) ∣ ) T[i] = int(2^{32}*|sin(i)|) T[i]=int(232∗∣sin(i)∣)
int 取整函数,sin 正弦函数,以 i 作为弧度输入。
各次迭代运算采用的T值:
var T = []uint32{
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8,
0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51,
0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905,
0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681,
0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60,
0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314,
0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
}
各次迭代运算采用的做循环移位s的值:
// 向左位移数
var s = []uint32{
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7,
12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10,
15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
}
// 下方函数为MD5加密算法的核心,迭代加密步骤
func trans(text string) {
// 将512-bit消息划分为16组
X := div_group(text)
var f, k uint32
// result存储最初的A,B,C,D
a := result[0]
b := result[1]
c := result[2]
d := result[3]
for i := uint32(0); i < uint32(64); i++ {
if i < 16 {
f = F(b, c, d)
k = i
} else if i < 32 {
f = G(b, c, d)
k = (5*i + 1) % 16
} else if i < 48 {
f = H(b, c, d)
k = (3*i + 5) % 16
} else {
f = I(b, c, d)
k = (7 * i) % 16
}
dtemp := d
d = c
c = b
b = b + (shift(a+f+T[i]+X[k], s[i]))
a = dtemp
}
result[0] = result[0] + a
result[1] = result[1] + b
result[2] = result[2] + c
result[3] = result[3] + d
}
加密结果如下:
// 下方三组数据来自wiki
The quick brown fox jumps over the lazy dog: 9e107d9d372bb6826bd81d3542a419d6
The quick brown fox jumps over the lazy cog: 1055d3e698d289f2af8663725127bd4b
: d41d8cd98f00b204e9800998ecf8427e //空字符串加密结果
完整代码详见Github