C/C++ MD5算法的实现代码

所属分类: 软件编程 / C 语言 阅读数: 95
收藏 0 赞 0 分享

在逆向程序的时候,经常会碰到加密的算法的问题,前面分析UC的逆向工程师的面试题2的时候,发现使用了MD5的加密算法(MD5算法是自己实现的,不是使用的算法库函数)。尤其是在逆向分析网络协议的时候,一般的程序使用的加密算法都是使用的库函数提供的算法,有些程序使用的算法是自己实现的;相对来说使用函数库提供的加密函数的算法相对来说比较好识别,因为有算法常见函数在;但是如果不是使用的函数库提供的加密的函数而是自己去实现某些算法话,识别起来有一定的难度,这就需要你对函数的加密原理以及流程还算法的特征比较熟悉才能很快识别出来。下面就将网上有关MD5算法一些知识整理一下,方面自己查阅。

md5简介

消息摘要算法第五版(英语:Message-Digest Algorithm 5,缩写为MD5),是当前计算机领域用于确保信息传输完整一致而广泛使用的散列算法之一(又译哈希算法、摘要算法等),主流编程语言普遍已有MD5的实现。将数据 (如一段文字)运算变为另一固定长度值,是散列算法的基础原理,MD5的前身有MD2、MD3和MD4。MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。目前,MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通 数据的错误检查领域。例如在一些BitTorrent下载中,软件将通过计算MD5检验下载到的文件片段的完整性。MD5已经广泛使用在为文件传输提供一定的可靠性方面。例如,服务器预先提供一个MD5校验和,用户下载完文件以后, 用MD5算法计算下载文件的MD5校验和,然后通过检查这两个校验和是否一致,就能判断下载的文件是否出错。MD5是输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个 128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

md5算法描述

假设输入信息(input message)的长度为b(bit),我们想要产生它的报文摘要,在此处b为任意的非负整数:b也可能为0,也不一定为8的整数倍,且可能是任意大的长度。设该信息的比特流表示如下: M[0] M[1] M[2] ... M[b-1] 计算此信息的报文摘要需要如下5步:

1.补位

信息计算前先要进行位补位,设补位后信息的长度为LEN(bit),则LEN%512 = 448(bit),即数据扩展至 K * 512 + 448(bit)。即K * 64+56(byte),K为整数。补位操作始终要执行,即使补位前信息的长度对512求余的结果是448。具体补位操作:补一个1,然后补0至满足上述要求。总共最少要补1bit,最多补512bit。

2.尾部加上信息长度

将输入信息的原始长度b(bit)表示成一个64-bit的数字,把它添加到上一步的结果后面(在32位的机器上,这64位将用2个字来表示并且低位在前)。当遇到b大于2^64这种极少的情况时,b的高位被截去,仅使用b的低64位。经过上面两步,数据就被填补成长度为512(bit)的倍数。也就是说,此时的数据长度是16个字(32byte)的整数倍。此时的数据表示为: M[0 ... N-1] 其中的N是16的倍数。

3.初始化缓存区

用一个四个字的缓冲器(A,B,C,D)来计算报文摘要,A,B,C,D分别是32位的寄存器,初始化使用的是十六进制表示的数字,注意低字节在前: word A: 01 23 45 67 word B: 89 ab cd ef word C: fe dc ba 98 word D: 76 54 32 10

4.转换

首先定义4个辅助函数,每个函数的输入是三个32位的字,输出是一个32位的字: F(X,Y,Z) = XY v not(X) Z G(X,Y,Z) = XZ v Y not(Z) H(X,Y,Z) = X xor Y xor Z I(X,Y,Z) = Y xor (X v not(Z))

FF(a,b,c,d,Mj,s,ti)表示 a = b + ((a + F(b,c,d) + Mj + ti) << s)
GG(a,b,c,d,Mj,s,ti)表示 a = b + ((a + G(b,c,d) + Mj + ti) << s)
HH(a,b,c,d,Mj,s,ti)表示 a = b + ((a + H(b,c,d) + Mj + ti) << s)
Ⅱ(a,b,c,d,Mj,s,ti)表示 a = b + ((a + I(b,c,d) + Mj + ti) << s)

这四轮(64步)是:

第一轮

FF(a,b,c,d,M0,7,0xd76aa478) FF(d,a,b,c,M1,12,0xe8c7b756) FF(c,d,a,b,M2,17,0x242070db) FF(b,c,d,a,M3,22,0xc1bdceee) FF(a,b,c,d,M4,7,0xf57c0faf) FF(d,a,b,c,M5,12,0x4787c62a) FF(c,d,a,b,M6,17,0xa8304613) FF(b,c,d,a,M7,22,0xfd469501) FF(a,b,c,d,M8,7,0x698098d8) FF(d,a,b,c,M9,12,0x8b44f7af) FF(c,d,a,b,M10,17,0xffff5bb1) FF(b,c,d,a,M11,22,0x895cd7be) FF(a,b,c,d,M12,7,0x6b901122) FF(d,a,b,c,M13,12,0xfd987193) FF(c,d,a,b,M14,17,0xa679438e) FF(b,c,d,a,M15,22,0x49b40821)

第二轮

GG(a,b,c,d,M1,5,0xf61e2562) GG(d,a,b,c,M6,9,0xc040b340) GG(c,d,a,b,M11,14,0x265e5a51) GG(b,c,d,a,M0,20,0xe9b6c7aa) GG(a,b,c,d,M5,5,0xd62f105d) GG(d,a,b,c,M10,9,0x02441453) GG(c,d,a,b,M15,14,0xd8a1e681) GG(b,c,d,a,M4,20,0xe7d3fbc8) GG(a,b,c,d,M9,5,0x21e1cde6) GG(d,a,b,c,M14,9,0xc33707d6) GG(c,d,a,b,M3,14,0xf4d50d87) GG(b,c,d,a,M8,20,0x455a14ed) GG(a,b,c,d,M13,5,0xa9e3e905) GG(d,a,b,c,M2,9,0xfcefa3f8) GG(c,d,a,b,M7,14,0x676f02d9) GG(b,c,d,a,M12,20,0x8d2a4c8a)

第三轮

HH(a,b,c,d,M5,4,0xfffa3942) HH(d,a,b,c,M8,11,0x8771f681) HH(c,d,a,b,M11,16,0x6d9d6122) HH(b,c,d,a,M14,23,0xfde5380c) HH(a,b,c,d,M1,4,0xa4beea44) HH(d,a,b,c,M4,11,0x4bdecfa9) HH(c,d,a,b,M7,16,0xf6bb4b60) HH(b,c,d,a,M10,23,0xbebfbc70) HH(a,b,c,d,M13,4,0x289b7ec6) HH(d,a,b,c,M0,11,0xeaa127fa) HH(c,d,a,b,M3,16,0xd4ef3085) HH(b,c,d,a,M6,23,0x04881d05) HH(a,b,c,d,M9,4,0xd9d4d039) HH(d,a,b,c,M12,11,0xe6db99e5) HH(c,d,a,b,M15,16,0x1fa27cf8) HH(b,c,d,a,M2,23,0xc4ac5665)

第四轮

Ⅱ(a,b,c,d,M0,6,0xf4292244) Ⅱ(d,a,b,c,M7,10,0x432aff97) Ⅱ(c,d,a,b,M14,15,0xab9423a7) Ⅱ(b,c,d,a,M5,21,0xfc93a039) Ⅱ(a,b,c,d,M12,6,0x655b59c3) Ⅱ(d,a,b,c,M3,10,0x8f0ccc92) Ⅱ(c,d,a,b,M10,15,0xffeff47d) Ⅱ(b,c,d,a,M1,21,0x85845dd1) Ⅱ(a,b,c,d,M8,6,0x6fa87e4f) Ⅱ(d,a,b,c,M15,10,0xfe2ce6e0) Ⅱ(c,d,a,b,M6,15,0xa3014314) Ⅱ(b,c,d,a,M13,21,0x4e0811a1) Ⅱ(a,b,c,d,M4,6,0xf7537e82) Ⅱ(d,a,b,c,M11,10,0xbd3af235) Ⅱ(c,d,a,b,M2,15,0x2ad7d2bb) Ⅱ(b,c,d,a,M9,21,0xeb86d391)

下面是MD5算法的具体的实现

MD5算法的头文件Md5.h:

#ifndef MD5_H  
#define MD5_H  
 
typedef struct 
{ 
  unsigned int count[2]; 
  unsigned int state[4]; 
  unsigned char buffer[64]; 
}MD5_CTX; 
 
 
#define F(x,y,z) ((x & y) | (~x & z))  
#define G(x,y,z) ((x & z) | (y & ~z))  
#define H(x,y,z) (x^y^z)  
#define I(x,y,z) (y ^ (x | ~z))  
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))  
 
#define FF(a,b,c,d,x,s,ac) { \ 
a += F(b, c, d) + x + ac; \ 
a = ROTATE_LEFT(a, s); \ 
a += b; \ 
} 
 
#define GG(a,b,c,d,x,s,ac) { \ 
  a += G(b, c, d) + x + ac; \ 
  a = ROTATE_LEFT(a, s); \ 
  a += b; \ 
} 
 
#define HH(a,b,c,d,x,s,ac) { \ 
  a += H(b, c, d) + x + ac; \ 
  a = ROTATE_LEFT(a, s); \ 
  a += b; \ 
} 
#define II(a,b,c,d,x,s,ac) { \ 
  a += I(b, c, d) + x + ac; \ 
  a = ROTATE_LEFT(a, s); \ 
  a += b; \ 
} 
 
 
void MD5Init(MD5_CTX *context); 
void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); 
void MD5Final(MD5_CTX *context, unsigned char digest[16]); 
void MD5Transform(unsigned int state[4], unsigned char block[64]); 
void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); 
void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); 
 
#endif

MD5算法的实现文件Md5.cpp:

unsigned char PADDING[] = {  
  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 
 
//在逆向代码的时候,需要关注下面的特征值 
void MD5Init(MD5_CTX *context) 
{ 
  context->count[0] = 0; 
  context->count[1] = 0; 
  context->state[0] = 0x67452301; 
  context->state[1] = 0xEFCDAB89; 
  context->state[2] = 0x98BADCFE; 
  context->state[3] = 0x10325476; 
} 
 
void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) 
{ 
  unsigned int i = 0, index = 0, partlen = 0; 
  index = (context->count[0] >> 3) & 0x3F; 
  partlen = 64 - index; 
  context->count[0] += inputlen << 3; 
  if (context->count[0] < (inputlen << 3)) 
    context->count[1]++; 
  context->count[1] += inputlen >> 29; 
 
  if (inputlen >= partlen) 
  { 
    memcpy(&context->buffer[index], input, partlen); 
    MD5Transform(context->state, context->buffer); 
    for (i = partlen; i + 64 <= inputlen; i += 64) 
      MD5Transform(context->state, &input[i]); 
    index = 0; 
  } 
  else 
  { 
    i = 0; 
  } 
  memcpy(&context->buffer[index], &input[i], inputlen - i); 
} 
 
void MD5Final(MD5_CTX *context, unsigned char digest[16]) 
{ 
  unsigned int index = 0, padlen = 0; 
  unsigned char bits[8]; 
  index = (context->count[0] >> 3) & 0x3F; 
  padlen = (index < 56) ? (56 - index) : (120 - index); 
  MD5Encode(bits, context->count, 8); 
  MD5Update(context, PADDING, padlen); 
  MD5Update(context, bits, 8); 
  MD5Encode(digest, context->state, 16); 
} 
 
void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) 
{ 
  unsigned int i = 0, j = 0; 
  while (j < len) 
  { 
    output[j] = input[i] & 0xFF; 
    output[j + 1] = (input[i] >> 8) & 0xFF; 
    output[j + 2] = (input[i] >> 16) & 0xFF; 
    output[j + 3] = (input[i] >> 24) & 0xFF; 
    i++; 
    j += 4; 
  } 
} 
 
void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) 
{ 
  unsigned int i = 0, j = 0; 
  while (j < len) 
  { 
    output[i] = (input[j]) | 
      (input[j + 1] << 8) | 
      (input[j + 2] << 16) | 
      (input[j + 3] << 24); 
    i++; 
    j += 4; 
  } 
} 
 
void MD5Transform(unsigned int state[4], unsigned char block[64]) 
{ 
  unsigned int a = state[0]; 
  unsigned int b = state[1]; 
  unsigned int c = state[2]; 
  unsigned int d = state[3]; 
  unsigned int x[64]; 
 
  MD5Decode(x, block, 64); 
  FF(a, b, c, d, x[0], 7, 0xd76aa478); 
  FF(d, a, b, c, x[1], 12, 0xe8c7b756); 
  FF(c, d, a, b, x[2], 17, 0x242070db); 
  FF(b, c, d, a, x[3], 22, 0xc1bdceee); 
  FF(a, b, c, d, x[4], 7, 0xf57c0faf); 
  FF(d, a, b, c, x[5], 12, 0x4787c62a); 
  FF(c, d, a, b, x[6], 17, 0xa8304613); 
  FF(b, c, d, a, x[7], 22, 0xfd469501); 
  FF(a, b, c, d, x[8], 7, 0x698098d8); 
  FF(d, a, b, c, x[9], 12, 0x8b44f7af); 
  FF(c, d, a, b, x[10], 17, 0xffff5bb1); 
  FF(b, c, d, a, x[11], 22, 0x895cd7be); 
  FF(a, b, c, d, x[12], 7, 0x6b901122); 
  FF(d, a, b, c, x[13], 12, 0xfd987193); 
  FF(c, d, a, b, x[14], 17, 0xa679438e); 
  FF(b, c, d, a, x[15], 22, 0x49b40821); 
 
 
  GG(a, b, c, d, x[1], 5, 0xf61e2562); 
  GG(d, a, b, c, x[6], 9, 0xc040b340); 
  GG(c, d, a, b, x[11], 14, 0x265e5a51); 
  GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); 
  GG(a, b, c, d, x[5], 5, 0xd62f105d); 
  GG(d, a, b, c, x[10], 9, 0x2441453); 
  GG(c, d, a, b, x[15], 14, 0xd8a1e681); 
  GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); 
  GG(a, b, c, d, x[9], 5, 0x21e1cde6); 
  GG(d, a, b, c, x[14], 9, 0xc33707d6); 
  GG(c, d, a, b, x[3], 14, 0xf4d50d87); 
  GG(b, c, d, a, x[8], 20, 0x455a14ed); 
  GG(a, b, c, d, x[13], 5, 0xa9e3e905); 
  GG(d, a, b, c, x[2], 9, 0xfcefa3f8); 
  GG(c, d, a, b, x[7], 14, 0x676f02d9); 
  GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); 
 
 
  HH(a, b, c, d, x[5], 4, 0xfffa3942); 
  HH(d, a, b, c, x[8], 11, 0x8771f681); 
  HH(c, d, a, b, x[11], 16, 0x6d9d6122); 
  HH(b, c, d, a, x[14], 23, 0xfde5380c); 
  HH(a, b, c, d, x[1], 4, 0xa4beea44); 
  HH(d, a, b, c, x[4], 11, 0x4bdecfa9); 
  HH(c, d, a, b, x[7], 16, 0xf6bb4b60); 
  HH(b, c, d, a, x[10], 23, 0xbebfbc70); 
  HH(a, b, c, d, x[13], 4, 0x289b7ec6); 
  HH(d, a, b, c, x[0], 11, 0xeaa127fa); 
  HH(c, d, a, b, x[3], 16, 0xd4ef3085); 
  HH(b, c, d, a, x[6], 23, 0x4881d05); 
  HH(a, b, c, d, x[9], 4, 0xd9d4d039); 
  HH(d, a, b, c, x[12], 11, 0xe6db99e5); 
  HH(c, d, a, b, x[15], 16, 0x1fa27cf8); 
  HH(b, c, d, a, x[2], 23, 0xc4ac5665); 
 
 
  II(a, b, c, d, x[0], 6, 0xf4292244); 
  II(d, a, b, c, x[7], 10, 0x432aff97); 
  II(c, d, a, b, x[14], 15, 0xab9423a7); 
  II(b, c, d, a, x[5], 21, 0xfc93a039); 
  II(a, b, c, d, x[12], 6, 0x655b59c3); 
  II(d, a, b, c, x[3], 10, 0x8f0ccc92); 
  II(c, d, a, b, x[10], 15, 0xffeff47d); 
  II(b, c, d, a, x[1], 21, 0x85845dd1); 
  II(a, b, c, d, x[8], 6, 0x6fa87e4f); 
  II(d, a, b, c, x[15], 10, 0xfe2ce6e0); 
  II(c, d, a, b, x[6], 15, 0xa3014314); 
  II(b, c, d, a, x[13], 21, 0x4e0811a1); 
  II(a, b, c, d, x[4], 6, 0xf7537e82); 
  II(d, a, b, c, x[11], 10, 0xbd3af235); 
  II(c, d, a, b, x[2], 15, 0x2ad7d2bb); 
  II(b, c, d, a, x[9], 21, 0xeb86d391); 
  state[0] += a; 
  state[1] += b; 
  state[2] += c; 
  state[3] += d; 
} 

MD5算法的调用测试:

int _tmain(int argc, _TCHAR* argv[]) 
{ 
 
  int i; 
  unsigned char encrypt[] = "admin";//21232f297a57a5a743894a0e4a801fc3  
  unsigned char decrypt[16]; 
 
  MD5_CTX md5; 
 
  MD5Init(&md5); 
  MD5Update(&md5, encrypt, strlen((char *)encrypt)); 
  MD5Final(&md5, decrypt); 
 
  //Md5加密后的32位结果 
  printf("加密前:%s\n加密后16位:", encrypt); 
  for (i = 4; i<12; i++) 
  { 
    printf("%02x", decrypt[i]);  
  } 
 
  //Md5加密后的32位结果 
  printf("\n加密前:%s\n加密后32位:", encrypt); 
  for (i = 0; i<16; i++) 
  { 
    printf("%02x", decrypt[i]);  
  } 
 
  getchar(); 
 
  return 0; 
}

上面的代码工程的下载地址:Md5Demo201707.zip

破解MD5加密的网址:http://www.cmd5.com/

感谢链接:
http://blog.sina.com.cn/s/blog_693de6100101kcu6.html

https://github.com/JieweiWei/md5

更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多