c++实现MD5 算法

用c++实现了md5算法。包含 md5.h 和md5.cpp 两个文件。

主要参考百度百科 “MD5” 原理的描述:http://baike.baidu.cn/view/7636.htm,代码中变量命名也是参考其中的公式,程序的使用说明在md5.h 文件的末尾注释中。

测试结果和百度百科测试例子一致。

实现过程中需要注意事项:最后把四个变量A B C D 链接成结果时 ,注意变量高低位的先后顺序,具体参考 LinkResult()方法。

md5.h

 1 #ifndef _MD5_H_
 2 #define _MD5_H_
 3 
 4 #include <iostream>
 5 #include <string>
 6 using namespace std;
 7 
 8 class MD5
 9 {
10     public:
11         typedef unsigned char uchar8; //make sure it is 8bit
12         typedef char char8; //make sure it is 8bit
13         MD5();
14         
15         void init();
16 
17         void UpdateMd5(const uchar8 input[], const int length);      
18         void UpdateMd5(const char8 input[], const int length);     
19         
20         void Finalize();
21         
22         void ComputMd5(const uchar8 input[], const int length); 
23         void ComputMd5(const char8 input[], const int length); 
24         
25         string GetMd5();
26         
27         void printMd5();
28         
29         
30     private:
31         typedef unsigned int uint32;       //make sure it is 32 bit;
32         typedef unsigned long long uint64; //make sure it is 64 bit;
33         uint32 A, B, C, D;
34         const static int blockLen_ = 64;    // 512/8                                  
35         //the remain after last updata (because md5 may be computed segment by segment)
36         uchar8 remain_[blockLen_];                    
37         int remainNum_ ;         // the number of remain_,  < 64 
38         uint64 totalInputBits_;
39         uchar8 md5Result_[16];   //bit style md5 result,totally 128 bit
40         char md5Result_hex_[33]; //hexadecimal style result; md5Result_hex_[32]='\0'
41         bool isDone_;            // indicate the comput is finished;
42                    
43         inline uint32 RotateLeft(const uint32 x, int n);
44         inline uint32 F(const uint32 x, const uint32 y, const uint32 z);
45         inline uint32 G(const uint32 x, const uint32 y, const uint32 z);
46         inline uint32 H(const uint32 x, const uint32 y, const uint32 z);
47         inline uint32 I(const uint32 x, const uint32 y, const uint32 z);
48         inline void FF(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
49                        const uint32 Mj, const int s, const uint32 ti);
50         inline void GG(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
51                        const uint32 Mj, const int s, const uint32 ti);
52         inline void HH(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
53                        const uint32 Mj, const int s, const uint32 ti);
54         inline void II(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
55                        const uint32 Mj, const int s, const uint32 ti);
56                        
57 
58         void UcharToUint(uint32 output[], const uchar8 input[], const unsigned int transLength);
59         
60         void FourRound(const uchar8 block[]);    
61 
62         void LinkResult();
63                     
64 };
65 
66 /* user guide
67    you can comput the md5 by using the funtion ComputMd5
68    eg:
69        MD5 m;
70        MD5::char8 str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
71        m.ComputMd5(str,sizeof(str) - 1);   
72        m.printMd5();
73 
74     if you want to comput segment by segment,you can do as follow, and init() is suggested 
75     the begging,and Finalize() must call in the end:
76         
77         MD5 M;
78         m.init();
79         MD5::uchar8 str1[] = "ABCDEFGHIJKLMN";
80         MD5::uchar8 str2[] = "OPQRSTUVWXYZabcdefghijk";
81         MD5::uchar8 str3[] = "lmnopqrstuvwxyz";
82         m.UpdateMd5(str1,sizeof(str1) - 1);
83         m.UpdateMd5(str2,sizeof(str2) - 1);
84         m.UpdateMd5(str3,sizeof(str3) - 1);
85         m.Finalize();
86         m.printMd5();
87 
88     if you want to comput the md5 of a file, you can use the interface of this program.
89 */
90 
91 #endif

md5.cpp

  1 #include”md5.h”

  2 
  3 #include<iostream>
  4 using namespace std;
  5 
  6 const int S[4][4] = {7, 12, 17, 22,
  7                      5, 9, 14, 20,
  8                      4, 11, 16, 23,
  9                      6, 10, 15, 21};
 10 void MD5::init()
 11 {
 12     A = 0x67452301;
 13     B = 0xefcdab89;
 14     C = 0x98badcfe;
 15     D = 0x10325476;
 16     remainNum_ = 0;
 17     remain_[0] = '\0';
 18     md5Result_hex_[0] = '\0';
 19     md5Result_[0] = '\0';
 20     totalInputBits_ = 0;
 21     isDone_ = false;
 22 }
 23 
 24 MD5::MD5()
 25 {
 26     init();
 27 }
 28 
 29 inline MD5::uint32 MD5::RotateLeft(const uint32 x, int n)
 30 {
 31     return (x << n) | (x >> (32-n));        
 32     // if x is signed, use: (x << n) | ((x & 0xFFFFFFFF) >> (32-n))
 33 }
 34 inline MD5::uint32 MD5::F(const uint32 x, const uint32 y, const uint32 z)
 35 {
 36     return (x & y) | ((~x) & z);
 37 }
 38 inline MD5::uint32 MD5::G(const uint32 x, const uint32 y, const uint32 z)
 39 {
 40     return (x & z) | (y & (~z));
 41 }
 42 inline MD5::uint32 MD5::H(const uint32 x, const uint32 y, const uint32 z)
 43 {
 44     return x ^ y ^ z;
 45 }
 46 inline MD5::uint32 MD5::I(const uint32 x, const uint32 y, const uint32 z)
 47 {
 48     return y ^ (x | (~z));
 49 }
 50 
 51 inline void MD5::FF(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
 52                     const uint32 Mj, const int s, const uint32 ti)
 53 {
 54     a = b + RotateLeft(a + F(b, c, d) + Mj + ti, s);
 55 }      
 56 inline void MD5::GG(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
 57                     const uint32 Mj, const int s, const uint32 ti)
 58 {
 59     a = b + RotateLeft(a + G(b, c, d) + Mj + ti, s);
 60 }                   
 61 inline void MD5::HH(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
 62                     const uint32 Mj, const int s, const uint32 ti)
 63 {
 64     a = b + RotateLeft(a + H(b, c, d) + Mj + ti, s);
 65 }                    
 66 inline void MD5::II(uint32 &a, const uint32 b, const uint32 c, const uint32 d,
 67                     const uint32 Mj, const int s, const uint32 ti)
 68 {
 69     a = b + RotateLeft(a + I(b, c, d) + Mj + ti, s);
 70 }          
 71 
 72 // link A B C D to result(bit style result and hexadecimal style result)
 73 void MD5::LinkResult()
 74 {
 75     //bit style result
 76     for(int i = 0; i < 4; i++)  //link A: low to high
 77     {
 78         md5Result_[i] = (A >> 8*i) & 0xff;
 79     }
 80     for(int i = 4; i<8; i++)   //link B: low to high
 81     {
 82         md5Result_[i] = (B >> 8*(i - 4)) & 0xff;
 83     }
 84     for(int i = 8; i<12; i++)  //link C: low to high
 85     {
 86         md5Result_[i] = (C >> 8*(i - 8)) & 0xff;
 87     }
 88     for(int i = 12; i<16; i++)  //link D: low to high
 89     {
 90         md5Result_[i] = (D >> 8*(i - 12)) & 0xff;
 91     }
 92 
 93     //change to hexadecimal style result
 94     // note: it is not the same as simply link hex(A) hex(B) hex(C) hex(D)
 95     for(int i = 0; i < 16; i++)
 96         sprintf(& md5Result_hex_[i*2], "%02x", md5Result_[i]);
 97     md5Result_hex_[32] = '\0';
 98 
 99 }
100 
101 //print the md5 by hex
102 void MD5::printMd5()
103 {
104     if(!isDone_)
105     {
106         cout<< "Error: computation is not finished" <<endl;
107         
108     }
109     else
110         cout<< "MD5 Value: " << md5Result_hex_ <<endl;
111 }
112 
113 //get the md5 value of hex style 
114 string MD5::GetMd5()
115 {
116     if(!isDone_)
117     {
118         cout<< "Error: computation is not finished" <<endl;
119         exit(0);
120     }
121     string a((const char *)md5Result_hex_);
122     return a;
123 }
124 
125 void MD5::UcharToUint(uint32 output[], const uchar8 input[], const unsigned int transLength)         
126 {
127     for(int i = 0, j = 0; j < transLength; i++, j += 4)
128     {
129         output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) |
130                 (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24);
131     }
132 }
133 
134 // four round on a block of 512 bits;
135 void MD5::FourRound(const uchar8 block[])
136 {
137     uint32 a = A, b = B, c = C, d = D;
138     uint32 M[16];
139     UcharToUint(M, block, blockLen_); //blockLen_ is a const int =64;
140     
141     //round 1
142     FF (a, b, c, d, M[ 0], S[0][0], 0xd76aa478); 
143     FF (d, a, b, c, M[ 1], S[0][1], 0xe8c7b756); 
144     FF (c, d, a, b, M[ 2], S[0][2], 0x242070db); 
145     FF (b, c, d, a, M[ 3], S[0][3], 0xc1bdceee); 
146     FF (a, b, c, d, M[ 4], S[0][0], 0xf57c0faf); 
147     FF (d, a, b, c, M[ 5], S[0][1], 0x4787c62a); 
148     FF (c, d, a, b, M[ 6], S[0][2], 0xa8304613);
149     FF (b, c, d, a, M[ 7], S[0][3], 0xfd469501);
150     FF (a, b, c, d, M[ 8], S[0][0], 0x698098d8); 
151     FF (d, a, b, c, M[ 9], S[0][1], 0x8b44f7af);
152     FF (c, d, a, b, M[10], S[0][2], 0xffff5bb1); 
153     FF (b, c, d, a, M[11], S[0][3], 0x895cd7be); 
154     FF (a, b, c, d, M[12], S[0][0], 0x6b901122);
155     FF (d, a, b, c, M[13], S[0][1], 0xfd987193);
156     FF (c, d, a, b, M[14], S[0][2], 0xa679438e);
157     FF (b, c, d, a, M[15], S[0][3], 0x49b40821); 
158 
159     // round 2 
160     GG (a, b, c, d, M[ 1], S[1][0], 0xf61e2562); 
161     GG (d, a, b, c, M[ 6], S[1][1], 0xc040b340); 
162     GG (c, d, a, b, M[11], S[1][2], 0x265e5a51); 
163     GG (b, c, d, a, M[ 0], S[1][3], 0xe9b6c7aa);
164     GG (a, b, c, d, M[ 5], S[1][0], 0xd62f105d); 
165     GG (d, a, b, c, M[10], S[1][1],  0x2441453); 
166     GG (c, d, a, b, M[15], S[1][2], 0xd8a1e681);
167     GG (b, c, d, a, M[ 4], S[1][3], 0xe7d3fbc8); 
168     GG (a, b, c, d, M[ 9], S[1][0], 0x21e1cde6);
169     GG (d, a, b, c, M[14], S[1][1], 0xc33707d6);
170     GG (c, d, a, b, M[ 3], S[1][2], 0xf4d50d87);
171     GG (b, c, d, a, M[ 8], S[1][3], 0x455a14ed); 
172     GG (a, b, c, d, M[13], S[1][0], 0xa9e3e905); 
173     GG (d, a, b, c, M[ 2], S[1][1], 0xfcefa3f8); 
174     GG (c, d, a, b, M[ 7], S[1][2], 0x676f02d9);
175     GG (b, c, d, a, M[12], S[1][3], 0x8d2a4c8a);
176 
177     //round 3 
178     HH (a, b, c, d, M[ 5], S[2][0], 0xfffa3942); 
179     HH (d, a, b, c, M[ 8], S[2][1], 0x8771f681); 
180     HH (c, d, a, b, M[11], S[2][2], 0x6d9d6122); 
181     HH (b, c, d, a, M[14], S[2][3], 0xfde5380c);
182     HH (a, b, c, d, M[ 1], S[2][0], 0xa4beea44); 
183     HH (d, a, b, c, M[ 4], S[2][1], 0x4bdecfa9);
184     HH (c, d, a, b, M[ 7], S[2][2], 0xf6bb4b60); 
185     HH (b, c, d, a, M[10], S[2][3], 0xbebfbc70); 
186     HH (a, b, c, d, M[13], S[2][0], 0x289b7ec6); 
187     HH (d, a, b, c, M[ 0], S[2][1], 0xeaa127fa); 
188     HH (c, d, a, b, M[ 3], S[2][2], 0xd4ef3085);
189     HH (b, c, d, a, M[ 6], S[2][3],  0x4881d05); 
190     HH (a, b, c, d, M[ 9], S[2][0], 0xd9d4d039); 
191     HH (d, a, b, c, M[12], S[2][1], 0xe6db99e5); 
192     HH (c, d, a, b, M[15], S[2][2], 0x1fa27cf8); 
193     HH (b, c, d, a, M[ 2], S[2][3], 0xc4ac5665); 
194   
195     //round 4 
196     II (a, b, c, d, M[ 0], S[3][0], 0xf4292244); 
197     II (d, a, b, c, M[ 7], S[3][1], 0x432aff97); 
198     II (c, d, a, b, M[14], S[3][2], 0xab9423a7); 
199     II (b, c, d, a, M[ 5], S[3][3], 0xfc93a039);
200     II (a, b, c, d, M[12], S[3][0], 0x655b59c3); 
201     II (d, a, b, c, M[ 3], S[3][1], 0x8f0ccc92); 
202     II (c, d, a, b, M[10], S[3][2], 0xffeff47d); 
203     II (b, c, d, a, M[ 1], S[3][3], 0x85845dd1); 
204     II (a, b, c, d, M[ 8], S[3][0], 0x6fa87e4f); 
205     II (d, a, b, c, M[15], S[3][1], 0xfe2ce6e0); 
206     II (c, d, a, b, M[ 6], S[3][2], 0xa3014314); 
207     II (b, c, d, a, M[13], S[3][3], 0x4e0811a1); 
208     II (a, b, c, d, M[ 4], S[3][0], 0xf7537e82); 
209     II (d, a, b, c, M[11], S[3][1], 0xbd3af235); 
210     II (c, d, a, b, M[ 2], S[3][2], 0x2ad7d2bb);
211     II (b, c, d, a, M[ 9], S[3][3], 0xeb86d391); 
212   
213     A += a;
214     B += b;
215     C += c;
216     D += d;
217 }
218 
219 // update md5,must consider the remain_.
220 void MD5::UpdateMd5(const uchar8 input[], const int length)
221 {    
222     isDone_ = false;
223     totalInputBits_ += (length << 3);
224     
225     int start = blockLen_ - remainNum_; //blockLen_ = 64
226     //copy a part of input to remain_ so it can form a block(size=64)
227   
228     if(start <= length)
229     {
230         // can form a block,then do FourRound to this block
231             memcpy(&remain_[remainNum_], input, start) ;
232             FourRound(remain_);
233 
234             int i;
235             for(i = start; i <= length - blockLen_; i += blockLen_)
236             {
237                 FourRound(&input[i]);
238             }
239             remainNum_ = length - i;  
240             memcpy(remain_, &input[i], remainNum_);  
241     }     
242     else
243     {
244         // can not form a block, function return;
245         memcpy(&remain_[remainNum_], input, length);
246         remainNum_ += length;
247     }    
248     
249 }
250 
251 void MD5::UpdateMd5(const char8 input[], const int length)
252 {
253     UpdateMd5((const uchar8 *)input, length);
254 }
255 
256 // padding with 100000... to remain_ and add the 64bit original size of input 
257 void MD5::Finalize()
258 {
259     if(isDone_ == true)
260         return;
261         
262     uchar8 padding[64] = {
263     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
264     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
265     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
266     };
267  
268     int temp = 56 - remainNum_;  //56 = 448/8
269     if(temp > 0)
270     {
271         UpdateMd5(padding, temp);
272         totalInputBits_ -= (temp << 3);
273     }
274     else if(temp < 0)
275     {
276         UpdateMd5(padding, 64 + temp);
277         totalInputBits_ -= ((64 + temp) << 3);
278     }
279  
280     // trans totalInputBits_ to uchar8 (64bits)
281     uchar8 Bits[8];
282     for(int i = 0; i < 8; i++)
283     {
284         Bits[i] = (totalInputBits_ >> 8*i) & 0xff;
285     }
286     
287     UpdateMd5(Bits, 8); // add the number of  original input (the last 64bits)
288     
289     LinkResult();
290     isDone_ = true;
291 }
292 
293 // comput the md5 based on input, (just this one input)
294 void MD5::ComputMd5(const uchar8 input[], const int length)
295 {
296     init();
297     UpdateMd5(input, length);
298     Finalize();
299 }
300 
301 void MD5::ComputMd5(const char8 input[], const int length)
302 {
303     ComputMd5((const uchar8 *)input, length);
304 }

标签