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)通过社会工程学来获取或者重新设置用户的口令。

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