Principle and implementation of MD5 encryption algorithm
MD5 message digest algorithm belongs to Hash algorithm. MD5 algorithm runs the message with arbitrary length to generate a 128 bit message summary.
The message length and filling data described below are in bits, and the byte order is small end bytes.
Algorithm principle
1. Data filling
Fill the message with data, so that the length of the message is 448 for 512, and set the message length as X, that is, X mod 512=448 is met. The data length to be filled is obtained according to this formula.
Filling method: fill after the message. The first digit is 1 and the rest is 0.
2. Add message length
After the result of the first step, fill in the length of the original message. The storage length available for processing is 64 bits. If the message length is greater than 264, only its lower 64 bit value is used, that is (message length modulo 264).
After this step, the final message length is an integer multiple of 512.
3. Data processing
Prepare the required data:
- Four constants: A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;
- Four functions: 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));
The message is divided into 512 bits as a packet for processing. Each packet is transformed for four rounds, calculated with the above four constants as the starting variables, re output four variables, and then carry out the operation of the next packet with these four variables. If it is the last packet, these four variables are the final result, that is, the MD5 value.
The implementation of specific calculation is complex. It is recommended to consult relevant books. The implementation code in C + + is given below.
code implementation
#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-bit cyclic left shift implementation function 7 void ltob(unsigned int &i); //B\L inter conversion, accept UINT type 8 unsigned int* MD5(const char* mStr); //Interface function and perform data filling. This function is called when calculating MD5 9 10 #endif
#MD5.cpp
1 #include "MD5.h" 2 3 /*4 Group calculation function*/ 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 End of group calculation function*/ 21 22 /*32 Bit cyclic left shift implementation function*/ 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 Inter conversion, receive UINT type*/ 31 void ltob(unsigned int &i) 32 { 33 unsigned int tmp = i;//Save copy 34 byte *psour = (byte*)&tmp, *pdes = (byte*)&i; 35 pdes += 3;//Adjust the pointer and prepare to turn left and right 36 for (short i = 3; i >= 0; --i) 37 { 38 CopyMemory(pdes - i, psour + i, 1); 39 } 40 return; 41 } 42 43 /* 44 MD5 Loop calculation function, label = the number of loops (1 < = label < = 4), lGroup array = 4 seed copies, M = data (16 groups of 32-bit pointers) 45 Seed array arrangement method: - A--D--C--B -- i.e. 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; //Definition: 4 pointers; T-meter accumulator; local variable 50 typedef unsigned int(*clac)(unsigned int X, unsigned int Y, unsigned int Z); //Define function type 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 };//Cyclic shift left - digit table 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 };//Data coordinate table 63 const unsigned int *pM = static_cast<unsigned int*>(M);//Convert type to 32-bit Uint 64 TAcc = ((label - 1) * 16) + 1; //Initialize the T-table accumulator according to the cycle number 65 clac clacArr[4] = { F, G, H, I }; //Defines and initializes an array of computed function pointers 66 67 /*Start of one cycle (16 groups - > 16 times)*/ 68 for (short i = 0; i < 16; ++i) 69 { 70 /*Perform pointer self transformation*/ 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 /*Start of calculation in the first step: A+F(B,C,D)+M[i]+T[i+1] Note: in the first step, calculate the T table directly*/ 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]);//Step 2: cycle left 79 *i1 = *i2 + tmpi;//Step 3: add and assign to seed 80 } 81 return; 82 } 83 84 /*Interface function and perform data filling*/ 85 unsigned int* MD5(const char* mStr) 86 { 87 unsigned int mLen = strlen(mStr); //Calculate string length 88 if (mLen < 0) return 0; 89 unsigned int FillSize = 448 - ((mLen * 8) % 512); //Calculate the number of bit s to be filled 90 unsigned int FSbyte = FillSize / 8; //Number of padding in bytes 91 unsigned int BuffLen = mLen + 8 + FSbyte; //Buffer length or the length after filling 92 unsigned char *md5Buff = new unsigned char[BuffLen]; //Allocate buffer 93 CopyMemory(md5Buff, mStr, mLen); //Copy string to buffer 94 95 /*Data fill start*/ 96 md5Buff[mLen] = 0x80; //The first bit is filled with 1 97 ZeroMemory(&md5Buff[mLen + 1], FSbyte - 1); //Other bit s are filled with 0, and another available function is FillMemory 98 unsigned long long lenBit = mLen * 8ULL; //Calculate the length of the string and prepare it for filling 99 CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, 8); //Filling length 100 /*End of data filling*/ 101 102 /*Operation start*/ 103 unsigned int LoopNumber = BuffLen / 64; //Take 16 words as a group and calculate the number of groups 104 unsigned int A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;//Initial 4 seeds, small end type 105 unsigned int *lGroup = new unsigned int[4]{ A, D, C, B}; //An array of seed copies and returned as a return value 106 for (unsigned int Bcount = 0; Bcount < LoopNumber; ++Bcount) //Start of grouping cycle 107 { 108 /*Enter the small cycle of 4 calculations*/ 109 for (unsigned short Lcount = 0; Lcount < 4;) 110 { 111 AccLoop(++Lcount, lGroup, &md5Buff[Bcount * 64]); 112 } 113 /*The data is added as the seed or final output of the next round*/ 114 A = (lGroup[0] += A); 115 B = (lGroup[3] += B); 116 C = (lGroup[2] += C); 117 D = (lGroup[1] += D); 118 } 119 /*Only after converting the layout in memory can it be displayed normally*/ 120 ltob(lGroup[0]); 121 ltob(lGroup[1]); 122 ltob(lGroup[2]); 123 ltob(lGroup[3]); 124 delete[] md5Buff; //Clear memory and return 125 return lGroup; 126 }
Then give the call example (take win32 console application as an example):
#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 << "Please enter a string to encrypt:"; 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; //The output value can only be seen at this breakpoint 20 }
Note: the above code was compiled on VS2013