MD5算法講解


MD5分析與代碼實現

 

 

 

 

 

 

 

一、 MD5密碼算法的特點

(1)    輸出總為16字節

(2)    不可逆性

(3)    高度離散性

(4)    抗碰撞性

 

 

二、 常用實例

(1)    密碼保護

(2)    文件完整性校驗【用於抗碰撞性高,可用於下載文件時,查看文件的md5於下載后,在檢驗一次md5值,如果相同,則文件沒有被修改,否則文件被修改了。從而實現文件完整性校驗】

(3)    數字簽名

(4)    雲盤秒傳【有時雲盤上傳時,在傳輸大文件的情況下,並不是真正實現秒傳。其實只需計算一次文件的Md5值,然后再數據庫中進行尋找,如果有相同的Md5,即直接引用即可】

 

三、 MD5算法的過程實現如下

(1)    數據補充

 MD5密碼算法,需要明文的長度為N*512+448bit,即數據的長度除以512位為448bit。但總長度要是512bit。其實很好奇,最后64bit去哪了。其實最后64bit需要單獨補充,作用是用來計算原始的數據長度。其次,補充的位數為1-521之間。補充的第一位為1,其次補充0.直到滿足mod512的結果為448。圖示如下。

 

 

 

(2)標准幻數

    標准幻數總共為4*4=16字節,看到這個16字節,是不是感覺到很熟悉。對的,它就跟MD5輸出16字節息息相關。

A = 01234567                      B = 89ABCDEF

C = FEDCBA98                      D = 76543210

這就是開始的標准幻數,這些就是作為循環計算的初始值用的。但需要注意的是,在程序中用的是小端字節序,也就是說高字節在前,低字節在后。即為如下所示

A = 0x67452301                    B = 0xEFCDB89

C = 0x98BADCFE                    D = 0x10325476

 

(3) 加密步驟

   1.原始數據分為n個512位,即n個64字節

   2.然后對每個512bit,即64字節分為16個4字節的數據。

4字節x[0]

4字節x[1]

4字節x[2]

4字節x[3]

4字節x[4]

4字節x[5]

4字節x[6]

4字節x[7]

4字節x[8]

4字節x[9]

4字節x[10]

4字節x[11]

4字節x[12]

4字節x[13]

4字節x[14]

4字節x[15]

 

3.准備4個函數

FF(A,B,C,D, X, S,AC);GG(A,B,C,D, X, S,AC);

HH(A,B,C,D, X, S,AC);II(A,B,C,D, X, S,AC);

 

4個標准幻數          分組的每4字節           固定常數

 

通過4個函數的邏輯運算於移位運算,改變第一個標准幻數的值,對於每4個字節,4個函數分別執行16次。

FF (A,B,C,D,x[0],S11,AC)

FF  (D,A,B,C,x[1],S12,AC)

……..

GG  (A,B,C,D,x[0],S21,AC)

……

HH  (A,B,C,D,x[0],S31,AC)

……

II  (A,B,C,D,x[0],S41,AC)

……

GG  (A,B,C,D,x[0],S44,AC)

 

這就是一輪計算,一輪計算后,改變了4個標准幻數的值。形成新的A,B,C,D。然后新的A,B,C,D於原來的A,B,C,D相加,從而形成新的標准幻數。

 

整個過程重復進行,知道所有的64字節處理完,得到最后的標准幻數。得到的最后的標准幻數即為MD5值。

例:

A = 0Xbfcbfgce                      B = 0Xc4105a80

C = 0X02599277                      D = 0X5c099ee2

 

MD5 = cefgcbbf805a10c477925202e29e095c

 

一、 C++代碼實現如下

  1 #include<iostream>
  2 #include<string>
  3 using namespace std;
  4 #define shift(x, n) (((x) << (n)) | ((x) >> (32-(n))))//右移的時候,高位一定要補零,而不是補充符號位
  5 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
  6 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
  7 #define H(x, y, z) ((x) ^ (y) ^ (z))
  8 #define I(x, y, z) ((y) ^ ((x) | (~z)))
  9 #define A 0x67452301
 10 #define B 0xefcdab89
 11 #define C 0x98badcfe
 12 #define D 0x10325476
 13 //strBaye的長度
 14 unsigned int strlength;
 15 //A,B,C,D的臨時變量
 16 unsigned int atemp;
 17 unsigned int btemp;
 18 unsigned int ctemp;
 19 unsigned int dtemp;
 20 //常量ti unsigned int(abs(sin(i+1))*(2pow32))
 21 const unsigned int k[]={
 22         0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
 23         0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
 24         0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
 25         0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
 26         0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
 27         0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
 28         0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
 29         0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
 30         0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
 31         0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
 32         0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
 33         0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
 34         0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
 35 //向左位移數
 36 const unsigned int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
 37         12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
 38         4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
 39         15,21,6,10,15,21,6,10,15,21,6,10,15,21};
 40 const char str16[]="0123456789abcdef";
 41 void mainLoop(unsigned int M[])
 42 {
 43     unsigned int f,g;
 44     unsigned int a=atemp;
 45     unsigned int b=btemp;
 46     unsigned int c=ctemp;
 47     unsigned int d=dtemp;
 48     for (unsigned int i = 0; i < 64; i++)
 49     {
 50         if(i<16){
 51             f=F(b,c,d);
 52             g=i;
 53         }else if (i<32)
 54         {
 55             f=G(b,c,d);
 56             g=(5*i+1)%16;
 57         }else if(i<48){
 58             f=H(b,c,d);
 59             g=(3*i+5)%16;
 60         }else{
 61             f=I(b,c,d);
 62             g=(7*i)%16;
 63         }
 64         unsigned int tmp=d;
 65         d=c;
 66         c=b;
 67         b=b+shift((a+f+k[i]+M[g]),s[i]);
 68         a=tmp;
 69     }
 70     atemp=a+atemp;
 71     btemp=b+btemp;
 72     ctemp=c+ctemp;
 73     dtemp=d+dtemp;
 74 }
 75 /*
 76 *填充函數
 77 *處理后應滿足bits≡448(mod512),字節就是bytes≡56(mode64)
 78 *填充方式為先加一個1,其它位補零
 79 *最后加上64位的原來長度
 80 */
 81 unsigned int* add(string str)
 82 {
 83     unsigned int num=((str.length()+8)/64)+1;//以512位,64個字節為一組
 84     unsigned int *strByte=new unsigned int[num*16];    //64/4=16,所以有16個整數
 85     strlength=num*16;
 86     for (unsigned int i = 0; i < num*16; i++)
 87         strByte[i]=0;
 88     for (unsigned int i=0; i <str.length(); i++)
 89     {
 90         strByte[i>>2]|=(str[i])<<((i%4)*8);//一個整數存儲四個字節,i>>2表示i/4 一個unsigned int對應4個字節,保存4個字符信息
 91     }
 92     strByte[str.length()>>2]|=0x80<<(((str.length()%4))*8);//尾部添加1 一個unsigned int保存4個字符信息,所以用128左移
 93     /*
 94     *添加原長度,長度指位的長度,所以要乘8,然后是小端序,所以放在倒數第二個,這里長度只用了32位
 95     */
 96     strByte[num*16-2]=str.length()*8;
 97     return strByte;
 98 }
 99 string changeHex(int a)
100 {
101     int b;
102     string str1;
103     string str="";
104     for(int i=0;i<4;i++)
105     {
106         str1="";
107         b=((a>>i*8)%(1<<8))&0xff;   //逆序處理每個字節
108         for (int j = 0; j < 2; j++)
109         {
110             str1.insert(0,1,str16[b%16]);
111             b=b/16;
112         }
113         str+=str1;
114     }
115     return str;
116 }
117 string getMD5(string source)
118 {
119     atemp=A;    //初始化
120     btemp=B;
121     ctemp=C;
122     dtemp=D;
123     unsigned int *strByte=add(source);
124     for(unsigned int i=0;i<strlength/16;i++)
125     {
126         unsigned int num[16];
127         for(unsigned int j=0;j<16;j++)
128             num[j]=strByte[i*16+j];
129         mainLoop(num);
130     }
131     return changeHex(atemp).append(changeHex(btemp)).append(changeHex(ctemp)).append(changeHex(dtemp));
132 }
133 
134 int main()
135 {
136     string ss;
137 //    cin>>ss;
138     string s=getMD5("abc");
139     cout<<s;
140     return 0;
141 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM