MD5加密算法Golang实现

什么是MD5?

MD5消息摘要算法(Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值,用于确保信息传输完整一致。MD5有MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。MD5广泛使用在为文件传输提供一定的可靠性方面。例如:服务器预先提供一个MD5校验和,用户下载完文件之后,用MD5算法计算下载文件的MD5校验和,然后通过检查这两个检验和是否一致,就能判断下载的文件是否出错。

MD5算法介绍

MD5算法处理不定长的输入信息,得到定长的128位输出。MD5将输入信息以512位进行分组,且每一分组又被划分为16个32位子分组,经过一系列处理之后算法的输出得到4个32位的输出,将此四个输出拼接起来就可以获得最终的加密结果。
MD5加密算法Golang实现_第1张图片
下面介绍算法的主要步骤:

  • 第一步:填充(padding)
    • 首先将输入信息用二进制串来表示,其长度设为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+p448(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} YL1。然后再将每个分组继续划分为16个32-bit长的子分组 X 0 X_0 X0 X 1 X_1 X1,…, X 15 X_{15} X15
  • 第三步:初始化
    初始化一个128-bit的MD缓冲区,记为 C V q CV_q CVq,表示成4个32-bit寄存器(A,B,C,D);其中, C V 0 = I V CV_0=IV CV0=IV。迭代在MD缓冲区进行,最后一步的128-bit输出结果结尾算法结果。寄存器(A,B,C,D)置16进制初初始值作为初始向量IV,并采用小端存储(little-endian)的存储结构:
	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,...L1)经过四轮循环压缩算法,表示为:
    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(CVi1,Yi)
    输出结果: M D = C V L MD = CV_L MD=CVL

  • 第五步:MD5压缩函数 H M D 5 H_{MD5} HMD5

    • H M D 5 H_{MD5} HMD5 C V CV CV输入128位,从消息分组输入512位,完成4轮循环后,输出128位,用于下一轮输入的 C V CV CV值。
    • 四轮循环中使用的生成函数轮函数是一个32位非线性逻辑函数(F,G,H,I中的一个)
    • 每轮循环分别为不同的生成函数(F,G,H,I),结果指定的T表示元素T[]和和消息分组的不同部分X[]做16次迭代运算,生成下一轮循环的输入。
    • 四轮循环总共有64次迭代运算。
  • 说明:

迭代运算如下:

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]的确定;

  • 第一轮循环:k = i (0~15)
    顺序使用X[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15]
  • 第二轮循环:k=(1+5i) mod 16 (16~31)
    顺序使用X[1, 6,11, 0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12]
  • 第三轮循环:k=(5+3i) mod 16(32~47)
    顺序使用X[5, 8,11,14, 1, 4, 7,10,13, 0, 3, 6, 9,12,15, 2]
  • 第四轮循环:k=7i mod 16(48~63)
    顺序使用X[0, 7,14, 5,12, 3,10, 1, 8,15, 6,13, 4,11, 2, 9]

T表定义如下:
T [ i ] = i n t ( 2 32 ∗ ∣ s i n ( i ) ∣ ) T[i] = int(2^{32}*|sin(i)|) T[i]=int(232sin(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

你可能感兴趣的:(Web安全)