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位的輸出,將此四個輸出拼接起來就可以獲得最終的加密結果。
下面介紹演算法的主要步驟:
- 第一步:填充(padding)
- 首先將輸入資訊用二進位制串來表示,其長度設為
k
bits,如果二進位制串長度k mod 512!=448
,則在該二進位制串最後面補充p
bits的標識,100…0(一個1和多個0),1≤p≤512,使得填充後的訊息位數滿足: - 然後,再向上述填充好的訊息尾部附加
k
值二進位制串表示的低64位(即 ),由於MD5加密演算法採用小端模式(little-endian),所以將此64位二進位制串的最後一個位元組放置在最前方,倒數第二個位元組放置在第二個自接觸,……,第一個位元組放置在最後方,最終處理過後的資訊長度為512的整數倍。
- 首先將輸入資訊用二進位制串來表示,其長度設為
- 第二步:分塊
把填充後的訊息結果分割為L
個512-bit分組: , ,…, 。然後再將每個分組繼續劃分為16個32-bit長的子分組 , ,…, - 第三步:初始化
初始化一個128-bit的MD緩衝區,記為 ,表示成4個32-bit暫存器(A,B,C,D);其中, 。迭代在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訊息分組為單位,每一份組 經過四輪迴圈壓縮演算法,表示為:
輸出結果: -
第五步:MD5壓縮函式
- 從 輸入128位,從訊息分組輸入512位,完成4輪迴圈後,輸出128位,用於下一輪輸入的 值。
- 四輪迴圈中使用的生成函式輪函式是一個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個元素,也稱為加法常數
<<<s
:將32位輸入迴圈左移s位
+
: 模
加法。
其中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
表定義如下:
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