Message Digest Algorithm MD5(中文名爲消息摘要算法),就是把一個任意長度的字節串變換成一個定長的十六進制數字串。算法
1、一致性驗證數據庫
MD5的典型應用是對一段信息(Message)產生信息摘要(Message-Digest)以防止被篡改。如咱們能夠在下載該軟件後,對下載回來的文件用專門的軟件(如Windows MD5 Check等)作一次MD5校驗,以確保咱們得到的文件與該站點提供的文件爲同一文件。利用MD5算法來進行文件校驗的方案被大量應用到軟件下載站、論壇數據庫、系統文件安全等方面。express
2、數字證書數組
MD5的典型應用是對一段Message(字節串)產生fingerprint(指紋),以防止被「篡改」。安全
3. 安全訪問認證app
MD5還普遍用於操做系統的登錄認證上,如Unix、各種BSD系統登陸密碼、數字簽名等諸多方面。如在UNⅨ系統中用戶的密碼是以MD5(或其它相似的算法)經Hash運算後存儲在文件系統中。當用戶登陸的時候,系統把用戶輸入的密碼進行MD5 Hash運算,而後再去和保存在文件系統中的MD5值進行比較,進而肯定輸入的密碼是否正確。經過這樣的步驟,系統在並不知道用戶密碼的明碼的狀況下就能夠肯定用戶登陸系統的合法性。ide
MD5算法的使用不須要支付任何版權費用,相對安全。函數
對MD5算法簡要的敘述能夠爲:MD5以512位分組來處理輸入的信息,且每一分組又被劃分爲16個32位子分組,通過了一系列的處理後,算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位散列值。oop
在MD5算法中,首先須要對信息進行填充,使其位長對512求餘的結果等於448。所以,信息的位長(Bits Length)將被擴展至N*512+448,N爲一個非負整數,N能夠是零。填充的方法以下,在信息的後面填充一個1和無數個0,直到知足上面的條件時才中止用0對信息的填充。而後,在這個結果後面附加一個以64位二進制表示的填充前信息長度。通過這兩步的處理,如今的信息的位長=N*512+448+64=(N+1)*512,即長度剛好是512的整數倍。這樣作的緣由是爲知足後面處理中對信息長度的要求。測試
MD5中有四個32位被稱做連接變量(Chaining Variable)的整數參數,他們分別爲:A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476。
當設置好這四個連接變量後,就開始進入算法的四輪循環運算。循環的次數是信息中512位信息分組的數目。
將上面四個連接變量複製到另外四個變量中:A到a,B到b,C到c,D到d。
主循環有四輪(MD4只有三輪),每輪循環都很類似。第一輪進行16次操做。每次操做對a、b、c和d中的其中三個做一次非線性函數運算,而後將所得結果加上第四個變量,文本的一個子分組和一個常數。再將所得結果向左環移一個不定的數,並加上a、b、c或d中之一。最後用該結果取代a、b、c或d中之一。
以一下是每次操做中用到的四個非線性函數(每輪一個)。
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))
(&;是與,|是或,~是非,^是異或)
這四個函數的說明:若是X、Y和Z的對應位是獨立和均勻的,那麼結果的每一位也應是獨立和均勻的。
F是一個逐位運算的函數。即,若是X,那麼Y,不然Z。函數H是逐位奇偶操做符。
假設Mj表示消息的第j個子分組(從0到15),常數ti是4294967296*abs(sin(i))的整數部分,i取值從1到64,單位是弧度。(4294967296等於2的32次方)
FF(a,b,c,d,Mj,s,ti)表示 a = b + ((a + F(b,c,d) + Mj + ti) << s)
GG(a,b,c,d,Mj,s,ti)表示 a = b + ((a + G(b,c,d) + Mj + ti) << s)
HH(a,b,c,d,Mj,s,ti)表示 a = b + ((a + H(b,c,d) + Mj + ti) << s)
Ⅱ(a,b,c,d,Mj,s,ti)表示 a = b + ((a + I(b,c,d) + Mj + ti) << s)
這四輪(64步)是:
第一輪
FF(a,b,c,d,M0,7,0xd76aa478)
FF(d,a,b,c,M1,12,0xe8c7b756)
FF(c,d,a,b,M2,17,0x242070db)
FF(b,c,d,a,M3,22,0xc1bdceee)
FF(a,b,c,d,M4,7,0xf57c0faf)
FF(d,a,b,c,M5,12,0x4787c62a)
FF(c,d,a,b,M6,17,0xa8304613)
FF(b,c,d,a,M7,22,0xfd469501)
FF(a,b,c,d,M8,7,0x698098d8)
FF(d,a,b,c,M9,12,0x8b44f7af)
FF(c,d,a,b,M10,17,0xffff5bb1)
FF(b,c,d,a,M11,22,0x895cd7be)
FF(a,b,c,d,M12,7,0x6b901122)
FF(d,a,b,c,M13,12,0xfd987193)
FF(c,d,a,b,M14,17,0xa679438e)
FF(b,c,d,a,M15,22,0x49b40821)
第二輪
GG(a,b,c,d,M1,5,0xf61e2562)
GG(d,a,b,c,M6,9,0xc040b340)
GG(c,d,a,b,M11,14,0x265e5a51)
GG(b,c,d,a,M0,20,0xe9b6c7aa)
GG(a,b,c,d,M5,5,0xd62f105d)
GG(d,a,b,c,M10,9,0x02441453)
GG(c,d,a,b,M15,14,0xd8a1e681)
GG(b,c,d,a,M4,20,0xe7d3fbc8)
GG(a,b,c,d,M9,5,0x21e1cde6)
GG(d,a,b,c,M14,9,0xc33707d6)
GG(c,d,a,b,M3,14,0xf4d50d87)
GG(b,c,d,a,M8,20,0x455a14ed)
GG(a,b,c,d,M13,5,0xa9e3e905)
GG(d,a,b,c,M2,9,0xfcefa3f8)
GG(c,d,a,b,M7,14,0x676f02d9)
GG(b,c,d,a,M12,20,0x8d2a4c8a)
第三輪
HH(a,b,c,d,M5,4,0xfffa3942)
HH(d,a,b,c,M8,11,0x8771f681)
HH(c,d,a,b,M11,16,0x6d9d6122)
HH(b,c,d,a,M14,23,0xfde5380c)
HH(a,b,c,d,M1,4,0xa4beea44)
HH(d,a,b,c,M4,11,0x4bdecfa9)
HH(c,d,a,b,M7,16,0xf6bb4b60)
HH(b,c,d,a,M10,23,0xbebfbc70)
HH(a,b,c,d,M13,4,0x289b7ec6)
HH(d,a,b,c,M0,11,0xeaa127fa)
HH(c,d,a,b,M3,16,0xd4ef3085)
HH(b,c,d,a,M6,23,0x04881d05)
HH(a,b,c,d,M9,4,0xd9d4d039)
HH(d,a,b,c,M12,11,0xe6db99e5)
HH(c,d,a,b,M15,16,0x1fa27cf8)
HH(b,c,d,a,M2,23,0xc4ac5665)
第四輪
Ⅱ(a,b,c,d,M0,6,0xf4292244)
Ⅱ(d,a,b,c,M7,10,0x432aff97)
Ⅱ(c,d,a,b,M14,15,0xab9423a7)
Ⅱ(b,c,d,a,M5,21,0xfc93a039)
Ⅱ(a,b,c,d,M12,6,0x655b59c3)
Ⅱ(d,a,b,c,M3,10,0x8f0ccc92)
Ⅱ(c,d,a,b,M10,15,0xffeff47d)
Ⅱ(b,c,d,a,M1,21,0x85845dd1)
Ⅱ(a,b,c,d,M8,6,0x6fa87e4f)
Ⅱ(d,a,b,c,M15,10,0xfe2ce6e0)
Ⅱ(c,d,a,b,M6,15,0xa3014314)
Ⅱ(b,c,d,a,M13,21,0x4e0811a1)
Ⅱ(a,b,c,d,M4,6,0xf7537e82)
Ⅱ(d,a,b,c,M11,10,0xbd3af235)
Ⅱ(c,d,a,b,M2,15,0x2ad7d2bb)
Ⅱ(b,c,d,a,M9,21,0xeb86d391)
全部這些完成以後,將A、B、C、D分別加上a、b、c、d。而後用下一分組數據繼續運行算法,最後的輸出是A、B、C和D的級聯。
當你按照我上面所說的方法實現MD5算法之後,你能夠用如下幾個信息對你作出來的程序做一個簡單的測試,看看程序有沒有錯誤。
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =
f29939a25efabaef3b87e2cbfe641315
Imports System
Imports System.Security.Cryptography
Imports System.Text
Module Example
' 哈希輸入字符串並返回一個32字符的十六進制字符串哈希。
Function getMd5Hash(ByVal input As String) As String
' 建立新的一個MD5CryptoServiceProvider對象的實例。
Dim md5Hasher As New MD5CryptoServiceProvider()
' 輸入的字符串轉換爲字節數組,並計算哈希。
Dim data As Byte() = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))
' 建立一個新的StringBuilder收集的字節,並建立一個字符串。
Dim sBuilder As New StringBuilder()
' 經過每一個字節的哈希數據和格式爲十六進制字符串的每個循環。
Dim i As Integer
For i = 0 To data.Length - 1
sBuilder.Append(data(i).ToString("x2"))
Next i
' 返回十六進制字符串。
Return sBuilder.ToString()
End Function
' 驗證對一個字符串的哈希值。
Function verifyMd5Hash(ByVal input As String,ByVal hash As String) As Boolean
' 哈希的輸入。
Dim hashOfInput As String = getMd5Hash(input)
' 建立StringComparer1的哈希進行比較。
Dim comparer As StringComparer = StringComparer.OrdinalIgnoreCase
If 0 = comparer.Compare(hashOfInput,hash) Then
Return True
Else
Return False
End If
End Function
Sub Main()
Dim source As String = "Hello World!"
Dim hash As String = getMd5Hash(source)
Console.WriteLine("進行MD5加密的字符串爲:" + source + " 加密的結果是:" + hash + ".")
Console.WriteLine("驗證哈希...")
If verifyMd5Hash(source,hash) Then
Console.WriteLine("哈希值是相同的。")
Else
Console.WriteLine("哈希值是不相同的。")
End If
End Sub
End Module
' 此代碼示例產生下面的輸出:
'
' 進行MD5加密的字符串爲:Hello World! 加密的結果是:ed076287532e86365e841e92bfc50d8c.
' 驗證哈希...
' 哈希值是相同的。
//Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
var int[64] r,k //r specifies the per-round shift amounts
r[ 0..15]:= {7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22}
r[16..31]:= {5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20}
r[32..47]:= {4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23}
r[48..63]:= {6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21}
//Use binary integer part of the sines of integers as constants:
for i from 0 to 63
k[i] := floor(abs(sin(i + 1)) × 2^32)
//Initialize variables:
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476
//Pre-processing:
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append bit length of message as 64-bit little-endian integer to message
//Process the message in successive 512-bit chunks:
for each 512-bit chunk of message
break chunk into sixteen 32-bit little-endian words w[i],0 ≤ i ≤ 15
//Initialize hash value for this chunk:
var int a := h0
var int b := h1
var int c := h2
var int d := h3
//Main loop:
for i from 0 to 63
if 0 ≤ i ≤ 15 then
f := (b and c) or ((not b) and d)
g := i
else if 16 ≤ i ≤ 31
f := (d and b) or ((not d) and c)
g := (5×i + 1) mod 16
else if 32 ≤ i ≤ 47
f := b xor c xor d
g := (3×i + 5) mod 16
else if 48 ≤ i ≤ 63
f := c xor (b or (not d))
g := (7×i) mod 16
temp := d
d := c
c := b
b := ((a + f + k[i] + w[g]) leftrotate r[i]) + b
a := temp
//Add this chunk's hash to result so far:
h0 := h0 + a
h1 := h1 + b
h2 := h2 + c
h3 := h3 + d
var int digest := h0 append h1 append h2 append h3
//(expressed as little-endian)