MD5加密

    MD5消息摘要算法(英語:MD5 Message-Digest Algorithm),一種被廣泛使用的密碼散列函數,可以產生出一個128位(16字節)的散列值(hash value),用於確保信息傳輸完整一致。MD5由美國密碼學家羅納德·李維斯特(Ronald Linn Rivest)設計,於1992年公開,用以取代MD4算法。

   

發展歷史

編輯

MD2

Rivest在1989年開發出MD2算法。在這個算法中,首先對信息進行數據補位,使信息的字節長度是16的倍數。然後,以一個16位的檢驗和追加到信息末尾,並且根據這個新產生的信息計算出散列值。後來,Rogier和Chauvaud發現如果忽略了檢驗和MD2將產生衝突。MD2算法加密後結果是唯一的(即不同信息加密後的結果不同)。

MD4

爲了加強算法的安全性,Rivest在1990年又開發出MD4算法。MD4算法同樣需要填補信息以確保信息的比特位長度減去448後能被512整除(信息比特位長度mod 512 = 448)。然後,一個以64位二進制表示的信息的最初長度被添加進來。信息被處理成512位damg?rd/merkle迭代結構的區塊,而且每個區塊要通過三個不同步驟的處理。Den boer和Bosselaers以及其他人很快的發現了攻擊MD4版本中第一步和第三步的漏洞。Dobbertin向大家演示瞭如何利用一部普通的個人電腦在幾分鐘內找到MD4完整版本中的衝突(這個衝突實際上是一種漏洞,它將導致對不同的內容進行加密卻可能得到相同的加密後結果)。毫無疑問,MD4就此被淘汰掉了。

儘管MD4算法在安全上有個這麼大的漏洞,但它對在其後才被開發出來的好幾種信息安全加密算法的出現卻有着不可忽視的引導作用。

MD5

1991年,Rivest開發出技術上更爲趨近成熟的md5算法。它在MD4的基礎上增加了"安全-帶子"(safety-belts)的概念。雖然MD5比MD4複雜度大一些,但卻更爲安全。這個算法很明顯的由四個和MD4設計有少許不同的步驟組成。在MD5算法中,信息-摘要的大小和填充的必要條件與MD4完全相同。Den boer和Bosselaers曾發現MD5算法中的假衝突(pseudo-collisions),但除此之外就沒有其他被發現的加密後結果了。

MD5應用

編輯

一致性驗證

MD5的典型應用是對一段信息(Message)產生信息摘要(Message-Digest),以防止被篡改。比如,在Unix下有很多軟件在下載的時候都有一個文件名相同,文件擴展名爲.md5的文件,在這個文件中通常只有一行文本,大致結構如: [1] 

MD5 (tanajiya.tar.gz) = 38b8c2c1093dd0fec383a9d9ac940515

這就是tanajiya.tar.gz文件的數字簽名。MD5將整個文件當作一個大文本信息,通過其不可逆的字符串變換算法,產生了這個唯一的MD5信息摘要。爲了讓讀者朋友對MD5的應用有個直觀的認識,筆者以一個比方和一個實例來簡要描述一下其工作過程:

大家都知道,地球上任何人都有自己獨一無二的指紋,這常常成爲司法機關鑑別罪犯身份最值得信賴的方法;與之類似,MD5就可以爲任何文件(不管其大小、格式、數量)產生一個同樣獨一無二的“數字指紋”,如果任何人對文件做了任何改動,其MD5值也就是對應的“數字指紋”都會發生變化。

我們常常在某些軟件下載站點的某軟件信息中看到其MD5值,它的作用就在於我們可以在下載該軟件後,對下載回來的文件用專門的軟件(如Windows MD5 Check等)做一次MD5校驗,以確保我們獲得的文件與該站點提供的文件爲同一文件。

具體來說文件的MD5值就像是這個文件的“數字指紋”。每個文件的MD5值是不同的,如果任何人對文件做了任何改動,其MD5值也就是對應的“數字指紋”就會發生變化。比如下載服務器針對一個文件預先提供一個MD5值,用戶下載完該文件後,用我這個算法重新計算下載文件的MD5值,通過比較這兩個值是否相同,就能判斷下載的文件是否出錯,或者說下載的文件是否被篡改了。MD5實際上一種有損壓縮技術,壓縮前文件一樣MD5值一定一樣,反之MD5值一樣並不能保證壓縮前的數據是一樣的。在密碼學上發生這樣的概率是很小的,所以MD5在密碼加密領域有一席之地。但是專業的黑客甚至普通黑客也可以利用MD5值實際是有損壓縮技術這一原理,將MD5的逆運算的值作爲一張表俗稱彩虹表的散列表來破解密碼。

利用MD5算法來進行文件校驗的方案被大量應用到軟件下載站、論壇數據庫、系統文件安全等方面。

數字簽名

MD5的典型應用是對一段Message(字節串)產生fingerprint(指紋),以防止被“篡改”。舉個例子,你將一段話寫在一個叫 readme.txt文件中,並對這個readme.txt產生一個MD5的值並記錄在案,然後你可以傳播這個文件給別人,別人如果修改了文件中的任何內容,你對這個文件重新計算MD5時就會發現(兩個MD5值不相同)。如果再有一個第三方的認證機構,用MD5還可以防止文件作者的“抵賴”,這就是所謂的數字簽名應用。

安全訪問認證

MD5還廣泛用於操作系統的登陸認證上,如Unix、各類BSD系統登錄密碼、數字簽名等諸多方面。如在Unix系統中用戶的密碼是以MD5(或其它類似的算法)經Hash運算後存儲在文件系統中。當用戶登錄的時候,系統把用戶輸入的密碼進行MD5 Hash運算,然後再去和保存在文件系統中的MD5值進行比較,進而確定輸入的密碼是否正確。通過這樣的步驟,系統在並不知道用戶密碼的明碼的情況下就可以確定用戶登錄系統的合法性。這可以避免用戶的密碼被具有系統管理員權限的用戶知道。MD5將任意長度的“字節串”映射爲一個128bit的大整數,並且是通過該128bit反推原始字符串是困難的,換句話說就是,即使你看到源程序和算法描述,也無法將一個MD5的值變換回原始的字符串,從數學原理上說,是因爲原始的字符串有無窮多個,這有點象不存在反函數的數學函數。所以,要遇到了md5密碼的問題,比較好的辦法是:你可以用這個系統中的md5()函數重新設一個密碼,如admin,把生成的一串密碼的Hash值覆蓋原來的Hash值就行了。

正是因爲這個原因,現在被黑客使用最多的一種破譯密碼的方法就是一種被稱爲"跑字典"的方法。有兩種方法得到字典,一種是日常蒐集的用做密碼的字符串表,另一種是用排列組合方法生成的,先用MD5程序計算出這些字典項的MD5值,然後再用目標的MD5值在這個字典中檢索。我們假設密碼的最大長度爲8位字節(8 Bytes),同時密碼只能是字母和數字,共26+26+10=62個字節,排列組合出的字典的項數則是P(62,1)+P(62,2)….+P(62,8),那也已經是一個很天文的數字了,存儲這個字典就需要TB級的磁盤陣列,而且這種方法還有一個前提,就是能獲得目標賬戶的密碼MD5值的情況下纔可以。這種加密技術被廣泛的應用於Unix系統中,這也是爲什麼Unix系統比一般操作系統更爲堅固一個重要原因。

算法原理

編輯

對MD5算法簡要的敘述可以爲:MD5以512位分組來處理輸入的信息,且每一分組又被劃分爲16個32位子分組,經過了一系列的處理後,算法的輸出由四個32位分組組成,將這四個32位分組級聯後將生成一個128位散列值。 [2] 

總體流程如下圖所示, 表示第i個分組,每次的運算都由前一輪的128位結果值和第i塊512bit值進行運算。

圖1.MD5算法的整體流程圖圖1.MD5算法的整體流程圖

代碼

編輯

C++實現

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

#include<iostream>

#include<string>

using namespace std;

#define shift(x, n) (((x) << (n)) | ((x) >> (32-(n))))//右移的時候,高位一定要補零,而不是補充符號位

#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))    

#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))

#define H(x, y, z) ((x) ^ (y) ^ (z))

#define I(x, y, z) ((y) ^ ((x) | (~z)))

#define A 0x67452301

#define B 0xefcdab89

#define C 0x98badcfe

#define D 0x10325476

//strBaye的長度

unsigned int strlength;

//A,B,C,D的臨時變量

unsigned int atemp;

unsigned int btemp;

unsigned int ctemp;

unsigned int dtemp;

//常量ti unsigned int(abs(sin(i+1))*(2pow32))

const unsigned int k[]={

        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};

//向左位移數

const unsigned int s[]={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};

const char str16[]="0123456789abcdef";

void mainLoop(unsigned int M[])

{

    unsigned int f,g;

    unsigned int a=atemp;

    unsigned int b=btemp;

    unsigned int c=ctemp;

    unsigned int d=dtemp;

    for (unsigned int i = 0; i < 64; i++)

    {

        if(i<16){

            f=F(b,c,d);

            g=i;

        }else if (i<32)

        {

            f=G(b,c,d);

            g=(5*i+1)%16;

        }else if(i<48){

            f=H(b,c,d);

            g=(3*i+5)%16;

        }else{

            f=I(b,c,d);

            g=(7*i)%16;

        }

        unsigned int tmp=d;

        d=c;

        c=b;

        b=b+shift((a+f+k[i]+M[g]),s[i]);

        a=tmp;

    }

    atemp=a+atemp;

    btemp=b+btemp;

    ctemp=c+ctemp;

    dtemp=d+dtemp;

}

/*

*填充函數

*處理後應滿足bits≡448(mod512),字節就是bytes≡56(mode64)

*填充方式爲先加一個1,其它位補零

*最後加上64位的原來長度

*/

unsigned int* add(string str)

{

    unsigned int num=((str.length()+8)/64)+1;//以512位,64個字節爲一組

    unsigned int *strByte=new unsigned int[num*16];    //64/4=16,所以有16個整數

    strlength=num*16;

    for (unsigned int i = 0; i < num*16; i++)

        strByte[i]=0;

    for (unsigned int i=0; i <str.length(); i++)

    {

        strByte[i>>2]|=(str[i])<<((i%4)*8);//一個整數存儲四個字節,i>>2表示i/4 一個unsigned int對應4個字節,保存4個字符信息

    }

    strByte[str.length()>>2]|=0x80<<(((str.length()%4))*8);//尾部添加1 一個unsigned int保存4個字符信息,所以用128左移

    /*

    *添加原長度,長度指位的長度,所以要乘8,然後是小端序,所以放在倒數第二個,這裏長度只用了32位

    */

    strByte[num*16-2]=str.length()*8;

    return strByte;

}

string changeHex(int a)

{

    int b;

    string str1;

    string str="";

    for(int i=0;i<4;i++)

    {

        str1="";

        b=((a>>i*8)%(1<<8))&0xff;   //逆序處理每個字節

        for (int j = 0; j < 2; j++)

        {

            str1.insert(0,1,str16[b%16]);

            b=b/16;

        }

        str+=str1;

    }

    return str;

}

string getMD5(string source)

{

    atemp=A;    //初始化

    btemp=B;

    ctemp=C;

    dtemp=D;

    unsigned int *strByte=add(source);

    for(unsigned int i=0;i<strlength/16;i++)

    {

        unsigned int num[16];

        for(unsigned int j=0;j<16;j++)

            num[j]=strByte[i*16+j];

        mainLoop(num);

    }

    return changeHex(atemp).append(changeHex(btemp)).append(changeHex(ctemp)).append(changeHex(dtemp));

}

unsigned int main()

{

    string ss;

//    cin>>ss;

    string s=getMD5("abc");

    cout<<s;

    return 0;

}

JAVA實現

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

public class MD5{

    /*

    *四個鏈接變量

    */

    private final int A=0x67452301;

    private final int B=0xefcdab89;

    private final int C=0x98badcfe;

    private final int D=0x10325476;

    /*

    *ABCD的臨時變量

    */

    private int Atemp,Btemp,Ctemp,Dtemp;

     

    /*

    *常量ti

    *公式:floor(abs(sin(i+1))×(2pow32)

    */

    private final int K[]={

        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};

    /*

    *向左位移數,計算方法未知

    */

    private final int s[]={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};

     

     

    /*

    *初始化函數

    */

    private void init(){

        Atemp=A;

        Btemp=B;

        Ctemp=C;

        Dtemp=D;

    }

    /*

    *移動一定位數

    */

    private    int    shift(int a,int s){

        return(a<<s)|(a>>>(32-s));//右移的時候,高位一定要補零,而不是補充符號位

    }

    /*

    *主循環

    */

    private void MainLoop(int M[]){

        int F,g;

        int a=Atemp;

        int b=Btemp;

        int c=Ctemp;

        int d=Dtemp;

        for(int i = 0; i < 64; i ++){

            if(i<16){

                F=(b&c)|((~b)&d);

                g=i;

            }else if(i<32){

                F=(d&b)|((~d)&c);

                g=(5*i+1)%16;

            }else if(i<48){

                F=b^c^d;

                g=(3*i+5)%16;

            }else{

                F=c^(b|(~d));

                g=(7*i)%16;

            }

            int tmp=d;

            d=c;

            c=b;

            b=b+shift(a+F+K[i]+M[g],s[i]);

            a=tmp;

        }

        Atemp=a+Atemp;

        Btemp=b+Btemp;

        Ctemp=c+Ctemp;

        Dtemp=d+Dtemp;

     

    }

    /*

    *填充函數

    *處理後應滿足bits≡448(mod512),字節就是bytes≡56(mode64)

    *填充方式爲先加一個0,其它位補零

    *最後加上64位的原來長度

    */

    private int[] add(String str){

        int num=((str.length()+8)/64)+1;//以512位,64個字節爲一組

        int strByte[]=new int[num*16];//64/4=16,所以有16個整數

        for(int i=0;i<num*16;i++){//全部初始化0

            strByte[i]=0;

        }

        int    i;

        for(i=0;i<str.length();i++){

            strByte[i>>2]|=str.charAt(i)<<((i%4)*8);//一個整數存儲四個字節,小端序

        }

        strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1

        /*

        *添加原長度,長度指位的長度,所以要乘8,然後是小端序,所以放在倒數第二個,這裏長度只用了32位

        */

        strByte[num*16-2]=str.length()*8;

            return strByte;

    }

    /*

    *調用函數

    */

    public String getMD5(String source){

        init();

        int strByte[]=add(source);

        for(int i=0;i<strByte.length/16;i++){

        int num[]=new int[16];

        for(int j=0;j<16;j++){

            num[j]=strByte[i*16+j];

        }

        MainLoop(num);

        }

        return changeHex(Atemp)+changeHex(Btemp)+changeHex(Ctemp)+changeHex(Dtemp);

     

    }

    /*

    *整數變成16進制字符串

    */

    private String changeHex(int a){

        String str="";

        for(int i=0;i<4;i++){

            str+=String.format("%2s", Integer.toHexString(((a>>i*8)%(1<<8))&0xff)).replace(' ''0');

 

        }

        return str;

    }

    /*

    *單例

    */

    private static MD5 instance;

    public static MD5 getInstance(){

        if(instance==null){

            instance=new MD5();

        }

        return instance;

    }

     

    private MD5(){};

     

    public static void main(String[] args){

        String str=MD5.getInstance().getMD5("");

        System.out.println(str);

    }

}

 

 

結果錯誤

1

 

VB2010實現

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

Imports System

 

Imports System.Security.Cryptography

 

Imports System.Text

 

 

Module Example

    '哈希輸入字符串並返回一個 32 字符的十六進制字符串哈希。

 

    Function GetMd5Hash(ByVal input As StringAs String

 

        '創建新的一個 MD5CryptoServiceProvider 對象的實例。

 

        Dim md5Hasher As New MD5CryptoServiceProvider()

 

        '輸入的字符串轉換爲字節數組,並計算哈希。

 

        Dim data As Byte() = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))

 

        '創建一個新的 StringBuilder 收集的字節,並創建一個字符串。

 

        Dim sBuilder As New StringBuilder()

 

        '通過每個字節的哈希數據和格式爲十六進制字符串的每一個循環。

 

        For As Integer = 0 To data.Length - 1

 

            sBuilder.Append(data(i).ToString("x2"))

 

        Next

 

        '返回十六進制字符串。

 

        Return sBuilder.ToString()

 

    End Function

 

 

    '驗證對一個字符串的哈希值。

 

    Function VerifyMd5Hash(ByVal input As StringByVal hash As StringAs Boolean

 

        '哈希的輸入。

 

        Dim hashOfInput As String = GetMd5Hash(input)

 

        '創建 StringComparer 的哈希進行比較。

 

        Dim comparer As StringComparer = StringComparer.OrdinalIgnoreCase

 

        Return comparer.Compare(hashOfInput, hash) = 0

 

    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("哈希值是不相同的。")

 

EndIf

 

    EndSub

 

EndModule

 

 

'此代碼示例產生下面的輸出:

 

 

'進行MD5加密的字符串爲:Hello World!,加密的結果是:ed076287532e86365e841e92bfc50d8c。

 

'正在驗證哈希……

 

'哈希值是相同的。

JavaScript實現

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

function md5(string) {

    function md5_RotateLeft(lValue, iShiftBits) {

        return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));

    }

    function md5_AddUnsigned(lX, lY) {

        var lX4, lY4, lX8, lY8, lResult;

        lX8 = (lX & 0x80000000);

        lY8 = (lY & 0x80000000);

        lX4 = (lX & 0x40000000);

        lY4 = (lY & 0x40000000);

        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);

        if (lX4 & lY4) {

            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);

        }

        if (lX4 | lY4) {

            if (lResult & 0x40000000) {

                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);

            else {

                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);

            }

        else {

            return (lResult ^ lX8 ^ lY8);

        }

    }

    function md5_F(x, y, z) {

        return (x & y) | ((~x) & z);

    }

    function md5_G(x, y, z) {

        return (x & z) | (y & (~z));

    }

    function md5_H(x, y, z) {

        return (x ^ y ^ z);

    }

    function md5_I(x, y, z) {

        return (y ^ (x | (~z)));

    }

    function md5_FF(a, b, c, d, x, s, ac) {

        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));

        return md5_AddUnsigned(md5_RotateLeft(a, s), b);

    };

    function md5_GG(a, b, c, d, x, s, ac) {

        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));

        return md5_AddUnsigned(md5_RotateLeft(a, s), b);

    };

    function md5_HH(a, b, c, d, x, s, ac) {

        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));

        return md5_AddUnsigned(md5_RotateLeft(a, s), b);

    };

    function md5_II(a, b, c, d, x, s, ac) {

        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));

        return md5_AddUnsigned(md5_RotateLeft(a, s), b);

    };

    function md5_ConvertToWordArray(string) {

        var lWordCount;

        var lMessageLength = string.length;

        var lNumberOfWords_temp1 = lMessageLength + 8;

        var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;

        var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;

        var lWordArray = Array(lNumberOfWords - 1);

        var lBytePosition = 0;

        var lByteCount = 0;

        while (lByteCount < lMessageLength) {

            lWordCount = (lByteCount - (lByteCount % 4)) / 4;

            lBytePosition = (lByteCount % 4) * 8;

            lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));

            lByteCount++;

        }

        lWordCount = (lByteCount - (lByteCount % 4)) / 4;

        lBytePosition = (lByteCount % 4) * 8;

        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);

        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;

        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;

        return lWordArray;

    };

    function md5_WordToHex(lValue) {

        var WordToHexValue = "",

        WordToHexValue_temp = "",

        lByte, lCount;

        for (lCount = 0; lCount <= 3; lCount++) {

            lByte = (lValue >>> (lCount * 8)) & 255;

            WordToHexValue_temp = "0" + lByte.toString(16);

            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);

        }

        return WordToHexValue;

    };

    function md5_Utf8Encode(string) {

        string = string.replace(/\r\n/g, "\n");

        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {

                utftext += String.fromCharCode(c);

            else if ((c > 127) && (c < 2048)) {

                utftext += String.fromCharCode((c >> 6) | 192);

                utftext += String.fromCharCode((c & 63) | 128);

            else {

                utftext += String.fromCharCode((c >> 12) | 224);

                utftext += String.fromCharCode(((c >> 6) & 63) | 128);

                utftext += String.fromCharCode((c & 63) | 128);

            }

        }

        return utftext;

    };

    var x = Array();

    var k, AA, BB, CC, DD, a, b, c, d;

    var S11 = 7,

    S12 = 12,

    S13 = 17,

    S14 = 22;

    var S21 = 5,

    S22 = 9,

    S23 = 14,

    S24 = 20;

    var S31 = 4,

    S32 = 11,

    S33 = 16,

    S34 = 23;

    var S41 = 6,

    S42 = 10,

    S43 = 15,

    S44 = 21;

    string = md5_Utf8Encode(string);

    x = md5_ConvertToWordArray(string);

    a = 0x67452301;

    b = 0xEFCDAB89;

    c = 0x98BADCFE;

    d = 0x10325476;

    for (k = 0; k < x.length; k += 16) {

        AA = a;

        BB = b;

        CC = c;

        DD = d;

        a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);

        d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);

        c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);

        b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);

        a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);

        d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);

        c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);

        b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);

        a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);

        d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);

        c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);

        b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);

        a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);

        d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);

        c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);

        b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);

        a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);

        d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);

        c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);

        b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);

        a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);

        d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);

        c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);

        b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);

        a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);

        d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);

        c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);

        b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);

        a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);

        d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);

        c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);

        b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);

        a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);

        d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);

        c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);

        b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);

        a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);

        d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);

        c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);

        b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);

        a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);

        d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);

        c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);

        b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);

        a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);

        d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);

        c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);

        b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);

        a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);

        d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);

        c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);

        b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);

        a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);

        d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);

        c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);

        b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);

        a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);

        d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);

        c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);

        b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);

        a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);

        d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);

        c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);

        b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);

        a = md5_AddUnsigned(a, AA);

        b = md5_AddUnsigned(b, BB);

        c = md5_AddUnsigned(c, CC);

        d = md5_AddUnsigned(d, DD);

    }

    return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();

}

 

MD5是一個安全的散列算法,輸入兩個不同的明文不會得到相同的輸出值,根據輸出值,不能得到原始的明文,即其過程不可逆;所以要解密MD5沒有現成的算法,只能用窮舉法,把可能出現的明文,用MD5算法散列之後,把得到的散列值和原始的數據形成一個一對一的映射表,通過比在表中比破解密碼的MD5算法散列值,通過匹配從映射表中找出破解密碼所對應的原始明文。

對信息系統或者網站系統來說,MD5算法主要用在用戶註冊口令的加密,對於普通強度的口令加密,可以通過以下三種方式進行破解:

(1)在線查詢密碼。一些在線的MD5值查詢網站提供MD5密碼值的查詢,輸入MD5密碼值後,如果在數據庫中存在,那麼可以很快獲取其密碼值。

(2)使用MD5破解工具。網絡上有許多針對MD5破解的專用軟件,通過設置字典來進行破解。

(3)通過社會工程學來獲取或者重新設置用戶的口令。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章