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

 更新时间:2017年07月23日 12:05:27   作者:Fly20141201  
下面就将网上有关MD5算法一些知识整理一下,方面自己查阅,需要的朋友可以参考下

在逆向程序的时候,经常会碰到加密的算法的问题,前面分析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++超详细分析顺序表

    C++超详细分析顺序表

    程序中经常需要将一组数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等。一组数据中包含的元素个数可能发生变化,顺序表则是将元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示
    2022-03-03
  • opencv实现颜色检测

    opencv实现颜色检测

    这篇文章主要为大家详细介绍了opencv实现颜色检测,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • C++实现简易通讯录功能

    C++实现简易通讯录功能

    这篇文章主要为大家详细介绍了C++实现简易通讯录功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 详解C++元编程之Parser Combinator

    详解C++元编程之Parser Combinator

    借助C++的constexpr能力,可以轻而易举的构造Parser Combinator,对用户定义的字符串(User defined literal)释放了巨大的潜力。
    2021-05-05
  • c++代码各种注释示例详解

    c++代码各种注释示例详解

    大家好,本篇文章主要讲的是c++代码各种注释示例详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • C语言实现扫雷小游戏详细代码

    C语言实现扫雷小游戏详细代码

    这篇文章主要为大家详细介绍了C语言实现扫雷小游戏的代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C/C++ Windows SAPI实现文字转语音功能

    C/C++ Windows SAPI实现文字转语音功能

    本文通过封装Windows SAPI(Speech Application Programming Interface),提供了一个现代化的C++接口实现文字转语音功能,这篇文章重点给大家介绍C/C++ Windows SAPI自实现文字转语音功能,感兴趣的朋友一起看看吧
    2025-02-02
  • c/c++中struct定义、声明、对齐方式解析

    c/c++中struct定义、声明、对齐方式解析

    这篇文章通过C/C++的两种声明方式开始,给大家详细分析了/c+中struct定义、声明、对齐方式,对此有兴趣的朋友可以参考学习下。
    2018-03-03
  • C++基于文件流与armadillo读取mnist示例详解

    C++基于文件流与armadillo读取mnist示例详解

    这篇文章主要给大家介绍了关于C++基于文件流与armadillo读取mnist的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • C/C++ QT实现自定义对话框的示例代码

    C/C++ QT实现自定义对话框的示例代码

    对话框分为多种,常见的有通用对话框,自定义对话框,模态对话框,非模态对话框等,本文主要介绍了QT自定义对话框,感兴趣的可以了解一下
    2021-11-11

最新评论