Principle and implementation of MD5 encryption algorithm

Posted by arion279 on Sun, 02 Jan 2022 20:37:40 +0100

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

 

 
Label: MD5

Topics: Algorithm