MD5加密算法原理及實現

MD5消息摘要算法,屬Hash算法一類。MD5算法對輸入任意長度的消息進行運行,產生一個128位的消息摘要。

以下所描述的消息長度、填充數據都以位(Bit)爲單位,字節序爲小端字節。

算法原理

1、數據填充

對消息進行數據填充,使消息的長度對512取模得448,設消息長度爲X,即滿足X mod 512=448。根據此公式得出需要填充的數據長度。

填充方法:在消息後面進行填充,填充第一位爲1,其餘爲0。

2、添加消息長度

在第一步結果之後再填充上原消息的長度,可用來進行的存儲長度爲64位。如果消息長度大於264,則只使用其低64位的值,即(消息長度 對 264取模)。

在此步驟進行完畢後,最終消息長度就是512的整數倍。

3、數據處理

準備需要用到的數據:

  • 4個常數: A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;
  • 4個函數: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));

把消息分以512位爲一分組進行處理,每一個分組進行4輪變換,以上面所說4個常數爲起始變量進行計算,重新輸出4個變量,以這4個變量再進行下一分組的運算,如果已經是最後一個分組,則這4個變量爲最後的結果,即MD5值。

具體計算的實現較爲複雜,建議查閱相關書籍,下面給出在C++上的實現代碼。

代碼實現

#MD5.h

複製代碼

 1 #ifndef MD5H
 2 #define MD5H
 3 #include <math.h>
 4 #include <Windows.h>
 5 
 6 void ROL(unsigned int &s, unsigned short cx); //32位數循環左移實現函數
 7 void ltob(unsigned int &i); //B\L互轉,接受UINT類型
 8 unsigned int* MD5(const char* mStr); //接口函數,並執行數據填充,計算MD5時調用此函數
 9 
10 #endif

複製代碼

#MD5.cpp

複製代碼

  1 #include "MD5.h"
  2 
  3 /*4組計算函數*/
  4 inline unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)
  5 {
  6     return (X & Y) | ((~X) & Z);
  7 }
  8 inline unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)
  9 {
 10     return (X & Z) | (Y & (~Z));
 11 }
 12 inline unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)
 13 {
 14     return X ^ Y ^ Z;
 15 }
 16 inline unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)
 17 {
 18     return Y ^ (X | (~Z));
 19 }
 20 /*4組計算函數結束*/
 21 
 22 /*32位數循環左移實現函數*/
 23 void ROL(unsigned int &s, unsigned short cx)
 24 {
 25     if (cx > 32)cx %= 32;
 26     s = (s << cx) | (s >> (32 - cx));
 27     return;
 28 }
 29 
 30 /*B\L互轉,接收UINT類型*/
 31 void ltob(unsigned int &i)
 32 {
 33     unsigned int tmp = i;//保存副本
 34     byte *psour = (byte*)&tmp, *pdes = (byte*)&i;
 35     pdes += 3;//調整指針,準備左右調轉
 36     for (short i = 3; i >= 0; --i)
 37     {
 38         CopyMemory(pdes - i, psour + i, 1);
 39     }
 40     return;
 41 }
 42 
 43 /*
 44 MD5循環計算函數,label=第幾輪循環(1<=label<=4),lGroup數組=4個種子副本,M=數據(16組32位數指針)
 45 種子數組排列方式: --A--D--C--B--,即 lGroup[0]=A; lGroup[1]=D; lGroup[2]=C; lGroup[3]=B;
 46 */
 47 void AccLoop(unsigned short label, unsigned int *lGroup, void *M)
 48 {
 49     unsigned int *i1, *i2, *i3, *i4, TAcc, tmpi = 0; //定義:4個指針; T表累加器; 局部變量
 50     typedef unsigned int(*clac)(unsigned int X, unsigned int Y, unsigned int Z); //定義函數類型
 51     const unsigned int rolarray[4][4] = {
 52         { 7, 12, 17, 22 },
 53         { 5, 9, 14, 20 },
 54         { 4, 11, 16, 23 },
 55         { 6, 10, 15, 21 }
 56     };//循環左移-位數表
 57     const unsigned short mN[4][16] = {
 58         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
 59         { 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 },
 60         { 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 },
 61         { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }
 62     };//數據座標表
 63     const unsigned int *pM = static_cast<unsigned int*>(M);//轉換類型爲32位的Uint
 64     TAcc = ((label - 1) * 16) + 1; //根據第幾輪循環初始化T表累加器
 65     clac clacArr[4] = { F, G, H, I }; //定義並初始化計算函數指針數組
 66 
 67     /*一輪循環開始(16組->16次)*/
 68     for (short i = 0; i < 16; ++i)
 69     {
 70         /*進行指針自變換*/
 71         i1 = lGroup + ((0 + i) % 4);
 72         i2 = lGroup + ((3 + i) % 4);
 73         i3 = lGroup + ((2 + i) % 4);
 74         i4 = lGroup + ((1 + i) % 4);
 75 
 76         /*第一步計算開始: A+F(B,C,D)+M[i]+T[i+1] 注:第一步中直接計算T表*/
 77         tmpi = (*i1 + clacArr[label - 1](*i2, *i3, *i4) + pM[(mN[label - 1][i])] + (unsigned int)(0x100000000UL * abs(sin((double)(TAcc + i)))));
 78         ROL(tmpi, rolarray[label - 1][i % 4]);//第二步:循環左移
 79         *i1 = *i2 + tmpi;//第三步:相加並賦值到種子
 80     }
 81     return;
 82 }
 83 
 84 /*接口函數,並執行數據填充*/
 85 unsigned int* MD5(const char* mStr)
 86 {
 87     unsigned int mLen = strlen(mStr); //計算字符串長度
 88     if (mLen < 0) return 0;
 89     unsigned int FillSize = 448 - ((mLen * 8) % 512); //計算需填充的bit數
 90     unsigned int FSbyte = FillSize / 8; //以字節表示的填充數
 91     unsigned int BuffLen = mLen + 8 + FSbyte; //緩衝區長度或者說填充後的長度
 92     unsigned char *md5Buff = new unsigned char[BuffLen]; //分配緩衝區
 93     CopyMemory(md5Buff, mStr, mLen); //複製字符串到緩衝區
 94 
 95     /*數據填充開始*/
 96     md5Buff[mLen] = 0x80; //第一個bit填充1
 97     ZeroMemory(&md5Buff[mLen + 1], FSbyte - 1); //其它bit填充0,另一可用函數爲FillMemory
 98     unsigned long long lenBit = mLen * 8ULL; //計算字符串長度,準備填充
 99     CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, 8); //填充長度
100     /*數據填充結束*/
101 
102     /*運算開始*/
103     unsigned int LoopNumber = BuffLen / 64; //以16個字爲一分組,計算分組數量
104     unsigned int A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;//初始4個種子,小端類型
105     unsigned int *lGroup = new unsigned int[4]{ A, D, C, B}; //種子副本數組,並作爲返回值返回
106     for (unsigned int Bcount = 0; Bcount < LoopNumber; ++Bcount) //分組大循環開始
107     {
108         /*進入4次計算的小循環*/
109         for (unsigned short Lcount = 0; Lcount < 4;)
110         {
111             AccLoop(++Lcount, lGroup, &md5Buff[Bcount * 64]);
112         }
113         /*數據相加作爲下一輪的種子或者最終輸出*/
114         A = (lGroup[0] += A);
115         B = (lGroup[3] += B);
116         C = (lGroup[2] += C);
117         D = (lGroup[1] += D);
118     }
119     /*轉換內存中的佈局後才能正常顯示*/
120     ltob(lGroup[0]);
121     ltob(lGroup[1]);
122     ltob(lGroup[2]);
123     ltob(lGroup[3]);
124     delete[] md5Buff; //清除內存並返回
125     return lGroup;
126 }

複製代碼

 

再給出調用實例(以win32控制檯應用程序爲例):

#main.cpp

複製代碼

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include "MD5.h"
 5 
 6 int main(int argc, char **argv)
 7 {
 8     char tmpstr[256], buf[4][10];
 9     std::cout << "請輸入要加密的字符串:";
10     std::cin >> tmpstr;
11     unsigned int* tmpGroup = MD5(tmpstr);
12     sprintf_s(buf[0], "%8X", tmpGroup[0]);
13     sprintf_s(buf[1], "%8X", tmpGroup[3]);
14     sprintf_s(buf[2], "%8X", tmpGroup[2]);
15     sprintf_s(buf[3], "%8X", tmpGroup[1]);
16     std::cout <<"MD5:"<< buf[0] << buf[1] << buf[2] << buf[3] << std::endl;
17     
18     delete[] tmpGroup;
19     return 0; //在此下斷點才能看到輸出的值
20 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章