MD5加密算法详细分析_C实现

MD5加密算法

本文为原创作品,转载请注明出处:http://write.blog.csdn.net/postedit/51736426——开心!


维基百科对其描述

MD5消息摘要算法英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由罗纳德·李维斯特设计,于1992年公开,用以替换MD4算法。这套算法的程序在 RFC 1321 中被加以规范。

数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理。


算法

Figure 1. 一个MD5运算— 由类似的64次循环构成,分成4组16次。 F 一个非线性函数;一个函数运算一次。 Mi 表示一个 32-bits 的输入数据, Ki 表示一个 32-bits 常数,用来完成每次不同的计算。

MD5是输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

{\displaystyle F(X,Y,Z)=(X\wedge {Y})\vee (\neg {X}\wedge {Z})} F(X,Y,Z) = (X\wedge{Y}) \vee (\neg{X} \wedge{Z})
{\displaystyle G(X,Y,Z)=(X\wedge {Z})\vee (Y\wedge \neg {Z})} G(X,Y,Z) = (X\wedge{Z}) \vee (Y \wedge \neg{Z})
{\displaystyle H(X,Y,Z)=X\oplus Y\oplus Z} H(X,Y,Z) = X \oplus Y \oplus Z
{\displaystyle I(X,Y,Z)=Y\oplus (X\vee \neg {Z})} I(X,Y,Z) = Y \oplus (X \vee \neg{Z})

{\displaystyle \oplus ,\wedge ,\vee ,\neg }\oplus, \wedge, \vee, \neg 是 XORANDOR , NOT 的符号。










更加详尽描述:

用途:

MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
  

MD5还广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的, 用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,而系统并不“知道”用户的密码是什么

原理:

       在一些初始化处理后,MD5以512位(64字节)分组来处理输入文本,每一分组又划分为16个32位(8字

)子分组。算法的输出由四个32(8字节)分组组成,将它们级联形成一个128位(32字节)散列值。 


在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448(56位)。因此,信息的位长将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充然后在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

  首先填充消息使其长度恰好为一个比512位的倍数仅小64位的数。填充方法是附一个1在消息后面,后接所要求的多个0,然后在其后附上64位的消息长度(填充前)。这两步的作用是使消息长度恰好是512位的整数倍(算法的其余部分要求如此),同时确保不同的消息在填充后不相同。 



四个32位变量初始化为: (这个为初始化变量,为固定值,经过研究所得)
A=0×01234567 
B=0×89abcdef 
C=0xfedcba98 
D=0×76543210 


它们称为链接变量(chaining variable)

 
  接着进行算法的主循环,循环的次数是消息中512位(64位)消息分组的数目。 

       将上面四个变量复制到别外的变量中:A到a,B到b,C到c,D到d。

  主循环有四轮(MD4只有三轮),每轮很相拟。第一轮进行16次操作。每次操作对a,b,c和d中的其中三个作一次非线性函数运算(利用下面非线性函数),然后将所得结果加上 第四个变量,文本的一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上a,b,c或d中之一。最后用该结果取代a,b,c或d中之一。 即下面的FF 、GG、HH、II函数
以一下是每次操作中用到的四个非线性函数(每轮一个)。 

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)) 

(&是与,|是或,~是非,^是异或) 

这些函数是这样设计的:(如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。 

函数F是按逐位方式操作:如果X,那么Y,否则Z。函数H是逐位奇偶操作符。)

设Mj表示消息的第j个子分组(从0到15),<<< s表示循环左移s位,则四种操作为: 
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) 
II(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,0×242070db) 
FF(b,c,d,a,M3,22,0xc1bdceee) 
FF(a,b,c,d,M4,7,0xf57c0faf) 
FF(d,a,b,c,M5,12,0×4787c62a) 
FF(c,d,a,b,M6,17,0xa8304613) 
FF(b,c,d,a,M7,22,0xfd469501) 
FF(a,b,c,d,M8,7,0×698098d8) 
FF(d,a,b,c,M9,12,0×8b44f7af) 
FF(c,d,a,b,M10,17,0xffff5bb1) 
FF(b,c,d,a,M11,22,0×895cd7be) 
FF(a,b,c,d,M12,7,0×6b901122) 
FF(d,a,b,c,M13,12,0xfd987193) 
FF(c,d,a,b,M14,17,0xa679438e) 
FF(b,c,d,a,M15,22,0×49b40821) 

第二轮 
GG(a,b,c,d,M1,5,0xf61e2562) 
GG(d,a,b,c,M6,9,0xc040b340) 
GG(c,d,a,b,M11,14,0×265e5a51) 
GG(b,c,d,a,M0,20,0xe9b6c7aa) 
GG(a,b,c,d,M5,5,0xd62f105d) 
GG(d,a,b,c,M10,9,0×02441453) 
GG(c,d,a,b,M15,14,0xd8a1e681) 
GG(b,c,d,a,M4,20,0xe7d3fbc8) 
GG(a,b,c,d,M9,5,0×21e1cde6) 
GG(d,a,b,c,M14,9,0xc33707d6) 
GG(c,d,a,b,M3,14,0xf4d50d87) 
GG(b,c,d,a,M8,20,0×455a14ed) 
GG(a,b,c,d,M13,5,0xa9e3e905) 
GG(d,a,b,c,M2,9,0xfcefa3f8) 
GG(c,d,a,b,M7,14,0×676f02d9) 
GG(b,c,d,a,M12,20,0×8d2a4c8a) 

第三轮 
HH(a,b,c,d,M5,4,0xfffa3942) 
HH(d,a,b,c,M8,11,0×8771f681) 
HH(c,d,a,b,M11,16,0×6d9d6122) 
HH(b,c,d,a,M14,23,0xfde5380c) 
HH(a,b,c,d,M1,4,0xa4beea44) 
HH(d,a,b,c,M4,11,0×4bdecfa9) 
HH(c,d,a,b,M7,16,0xf6bb4b60) 
HH(b,c,d,a,M10,23,0xbebfbc70) 
HH(a,b,c,d,M13,4,0×289b7ec6) 
HH(d,a,b,c,M0,11,0xeaa127fa) 
HH(c,d,a,b,M3,16,0xd4ef3085) 
HH(b,c,d,a,M6,23,0×04881d05) 
HH(a,b,c,d,M9,4,0xd9d4d039) 
HH(d,a,b,c,M12,11,0xe6db99e5) 
HH(c,d,a,b,M15,16,0×1fa27cf8) 
HH(b,c,d,a,M2,23,0xc4ac5665) 

第四轮 
II(a,b,c,d,M0,6,0xf4292244) 
II(d,a,b,c,M7,10,0×432aff97) 
II(c,d,a,b,M14,15,0xab9423a7) 
II(b,c,d,a,M5,21,0xfc93a039) 
II(a,b,c,d,M12,6,0×655b59c3) 
II(d,a,b,c,M3,10,0×8f0ccc92) 
II(c,d,a,b,M10,15,0xffeff47d) 
II(b,c,d,a,M1,21,0×85845dd1) 
II(a,b,c,d,M8,6,0×6fa87e4f) 
II(d,a,b,c,M15,10,0xfe2ce6e0) 
II(c,d,a,b,M6,15,0xa3014314) 
II(b,c,d,a,M13,21,0×4e0811a1) 
II(a,b,c,d,M4,6,0xf7537e82) 
II(d,a,b,c,M11,10,0xbd3af235) 
II(c,d,a,b,M2,15,0×2ad7d2bb) 
II(b,c,d,a,M9,21,0xeb86d391) 
  

常数ti可以如下选择: 
在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度。 

(2的32次方) 


所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输

出是A,B,C和D的级联。 


下面看代码,其中进行了十分详细的注释(代码经过linux下测试与传统MD5加密相同):


  1. /************************************************************************* 
  2.     > File Name: md5_1.cpp 
  3.     > Author:chudongfang  
  4.     > Mail:1149669942@qq.com  
  5.     > Created Time: 2016年06月22日 星期三 16时12分30秒 
  6.  ************************************************************************/  
  7.    
  8. #include <string.h>  
  9. #include <math.h>  
  10. #include <stdio.h>  
  11.    
  12.   
  13. /*********************************** 
  14.  * 非线性函数 
  15.  * (&是与,|是或,~是非,^是异或)  
  16.  *  
  17.  * 这些函数是这样设计的: 
  18.  *   如果X、Y和Z的对应位是独立和均匀的, 
  19.  *   那么结果的每一位也应是独立和均匀的。  
  20.  *  
  21.  * 函数F是按逐位方式操作:如果X,那么Y,否则Z。 
  22.  * 函数H是逐位奇偶操作符 
  23.  **********************************/  
  24. #define F(x,y,z) ((x & y) | (~x & z))    
  25. #define G(x,y,z) ((x & z) | (y & ~z))    
  26. #define H(x,y,z) (x^y^z)    
  27. #define I(x,y,z) (y ^ (x | ~z))    
  28.   
  29.   
  30. /************************************** 
  31.  *向右环移n个单位 
  32.  * ************************************/  
  33. #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))    
  34.   
  35.   
  36.   
  37.   
  38. /**************************************************** 
  39.  * 每次操作对a,b,c和d中的其中三个作一次非线性函数运算 
  40.  *  F(b,c,d)   G(b,c,d)   H(b,c,d)   I(b,c,d) 
  41.  * 
  42.  * 然后将所得结果加上 第四个变量(a), 
  43.  * F(b,c,d)+a 
  44.  * 
  45.  * 文本的一个子分组(x) 
  46.  * F(b,c,d)+a+x 
  47.  *  
  48.  * 和一个常数(ac)。 
  49.  * F(b,c,d)+a+x+ac 
  50.  * 
  51.  * 再将所得结果向右环移一个不定的数(s), 
  52.  * ROTATE_LEFT( F(b,c,d)+a+x+ac , s ) 
  53.  *  
  54.  * 并加上a,b,c或d中之一(b)。 
  55.  * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b 
  56.  *  
  57.  * 最后用该结果取代a,b,c或d中之一(a)。 
  58.  * a=ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b 
  59.  *  
  60.  * ***************************************************/  
  61.   
  62.   
  63. #define FF(a,b,c,d,x,s,ac) { a += F(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  64. #define GG(a,b,c,d,x,s,ac) { a += G(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  65. #define HH(a,b,c,d,x,s,ac) { a += H(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  66. #define II(a,b,c,d,x,s,ac) { a += I(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  67.   
  68.   
  69.   
  70.   
  71.   
  72. //储存一个MD5 text信息   
  73. typedef struct    
  74. {    
  75.     unsigned int count[2];      
  76.     //记录当前状态,其数据位数     
  77.       
  78.     unsigned int state[4];      
  79.     //4个数,一共32位 记录用于保存对512bits信息加密的中间结果或者最终结果    
  80.       
  81.     unsigned char buffer[64];  
  82.     //一共64字节,512位        
  83. }MD5_CTX;    
  84.     
  85.   
  86.   
  87. //第一位1 其后若干个0,用于MD5Final函数时的补足  
  88. unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  89. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  90. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  91. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};    
  92.     
  93.   
  94.   
  95. //函数声明区,每个函数在下面都有较详细说明,这里不再赘述  
  96.   
  97. void MD5Init(MD5_CTX *context);    
  98.   
  99. void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);    
  100.   
  101. void MD5Final(MD5_CTX *context,unsigned char digest[16]);    
  102.   
  103. void MD5Transform(unsigned int state[4],unsigned char block[64]);    
  104.   
  105. void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);    
  106.   
  107. void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);    
  108.     
  109.   
  110.   
  111.   
  112.   
  113. /************************ 
  114.  * 函数功能:初始化一个MD5 text 
  115.  * 函数参数:MD5 text 指针 
  116.  * ***********************/  
  117. //初始化  
  118. void MD5Init(MD5_CTX *context)    
  119. {    
  120.     context->count[0] = 0;    
  121.     context->count[1] = 0;     
  122.     //分别赋固定值    
  123.     context->state[0] = 0x67452301;  
  124.     context->state[1] = 0xEFCDAB89;    
  125.     context->state[2] = 0x98BADCFE;    
  126.     context->state[3] = 0x10325476;    
  127. }    
  128.   
  129.   
  130. /************************************************ 
  131.  * 函数功能:对一个MD5 text,把输入的数据进行分组,并进行加密 
  132.  * 未用到的数据把其储存在MD5 text中。 
  133.  * 
  134.  * 参数分析: 
  135.  * MD5_CTX *context       :一个MD5 text    
  136.  * unsigned char *input   :新添加的数据   
  137.  * unsigned int inputlen  :新添加数据的长度(字节) 
  138.  * 
  139.  ***********************************************/  
  140.   
  141. void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)    
  142. {    
  143.     unsigned int i = 0,index = 0,partlen = 0;    
  144.       
  145.     //index:当前状态的位数对64取余,其单位是字节  
  146.     //也可以写作:  index=(context->count[0]/8)%64  
  147.     index = (context->count[0] >> 3) & 0x3F;    
  148.       
  149.     //partlen:可以补齐64字节的字节数  
  150.     partlen = 64 - index;    
  151.       
  152.     //下面代码是解决一个unsignde int 无法储存极大数据导致溢出的问题  
  153.     //当前位数加上新添加的位数,由于inputlen是以字节为单位,所以其转换为位数  
  154.     //相当于context->count[0] += inputlen*8;    
  155.     context->count[0] += inputlen << 3;    
  156.      
  157.     //当其出现溢出的情况时,通过以下操作把两个16位的数连在一块,生成一个  
  158.     //32位的二进制数串,从而扩大其储存范围  
  159.     if(context->count[0] < (inputlen << 3))    
  160.         context->count[1]++;  
  161.       
  162.     //该语句可替换为 context->count[1]+=(inputlen<<3)>>32;  
  163.     //便于理解  
  164.     context->count[1] += inputlen >> 29;    
  165.       
  166.     //当其输入字节数的大于其可以补足64字节的字节数,进行补足  
  167.     if(inputlen >= partlen)    
  168.     {    
  169.         //向buffer中补足partlen个字节,使其到达64字节  
  170.         memcpy(&context->buffer[index],input,partlen);  
  171.           
  172.         //buffer达到64字节512位,则把其作为一组进行运算  
  173.         MD5Transform(context->state,context->buffer);    
  174.           
  175.         //如果输入的数据还可以组成多个64字节,则把其可以组成  
  176.         //的作为若干组进行运算  
  177.         for(i = partlen;i+64 <= inputlen;i+=64)    
  178.             MD5Transform(context->state,&input[i]);    
  179.           
  180.         //恢复0值,照应 下面 把输入 剩余字节(不能组成64字节组) 储存的操作  
  181.         index = 0;            
  182.     }     
  183.     //否则,把输入的数据按顺序放在原来数据后面  
  184.     else    
  185.     {    
  186.         i = 0;    
  187.     }    
  188.   
  189.     //放置剩余数据  
  190.     memcpy(&context->buffer[index],&input[i],inputlen-i);    
  191. }    
  192.   
  193.   
  194.   
  195.   
  196. /************************************************* 
  197.  * 函数功能:对数据进行补足,并加入数据位数信息,并进一步加密 
  198.  *  
  199.  * 参数分析: 
  200.  * MD5_CTX *context          :一个MD5 text 
  201.  * unsigned char digest[16]  :储存加密结果的数组 
  202.  *************************************************/  
  203.   
  204. void MD5Final(MD5_CTX *context,unsigned char digest[16])    
  205. {    
  206.     unsigned int index = 0,padlen = 0;    
  207.       
  208.     //bits: 8个字节,64位  
  209.     unsigned char bits[8];    
  210.       
  211.     //index:对64取余结果  
  212.     index = (context->count[0] >> 3) & 0x3F;    
  213.     //因为要填充满足使其位长对512求余的结果等于448(56位)  
  214.     //所以当其所剩余的数小于56字节,则填充56-index字节,  
  215.     //否则填充120-index字节  
  216.     //这里padlen代表其所需填充的字节  
  217.     padlen = (index < 56)?(56-index):(120-index);    
  218.       
  219.     //然后,在这个结果后面附加一个以64位二进制表示的填充前数据长度。  
  220.     //把填充前数据数据长度转换后放到bit字符数组中  
  221.     MD5Encode(bits,context->count,8);  
  222.       
  223.     //根据已经存储好的数组PADDING,在信息的后面填充一个1和无数个0,  
  224.     //直到满足上面的条件时才停止用0对信息的填充  
  225.     //其填充后进行了一系列的加密操作,其定剩余48个字节  
  226.     MD5Update(context,PADDING,padlen);    
  227.   
  228.     //在最后添加进8个字节的数据长度信息,最后凑成一组,进行一次加密处理  
  229.     MD5Update(context,bits,8);    
  230.       
  231.     //把最终得到的加密信息变成字符输出,共16字节  
  232.     MD5Encode(digest,context->state,16);    
  233. }    
  234.   
  235.   
  236.   
  237.   
  238. /********************************************************** 
  239.  * 函数功能:利用位操作,按1->4方式把数字分解成字符 
  240.  * 
  241.  * 参数分析: 
  242.  * unsigned char  *output :输出的字符的数组 
  243.  * unsigned int   *input  :输入数字的数组 
  244.  * unsigned int   len     : 输入数字数组的长度(单位:位)  
  245.  * *********************************************************/  
  246.   
  247. void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)    
  248. {    
  249.     unsigned int i = 0,j = 0;    
  250.     while(j < len)    
  251.     {    
  252.         //这里& 0xFF为取后8位  
  253.         //i代表数字数组下标  
  254.         //j代表字符数组下标  
  255.         //把数字的8、8-16、16-24、24-32分别赋值给字符  
  256.         output[j] = input[i] & 0xFF;      
  257.         output[j+1] = (input[i] >> 8) & 0xFF;    
  258.         output[j+2] = (input[i] >> 16) & 0xFF;    
  259.         output[j+3] = (input[i] >> 24) & 0xFF;    
  260.         i++;    
  261.         j+=4;    
  262.     }    
  263. }    
  264.   
  265.   
  266.   
  267.   
  268. /********************************************************** 
  269.  * 函数功能:利用位操作,按4->1方式把字符合成数字 
  270.  * 
  271.  * 参数分析: 
  272.  * unsigned int  *output :输出的数字的数组 
  273.  * unsigned char *input  :输入字符的数组 
  274.  * unsigned int  len     : 输入字符的长度 (单位:位) 
  275.  * *********************************************************/  
  276.   
  277. void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)    
  278. {    
  279.     unsigned int i = 0,j = 0;    
  280.     while(j < len)    
  281.     {    
  282.         //利用位操作,把四个单位为1字节的字符,合成一个单位为4字节的数字  
  283.         //因为FF GG HH II和非线性函数都只能对数字进行处理  
  284.         //第一个字符占前8位,第二个占8-16位,第三个占16-24位,第四个占  
  285.         //24-32位。  
  286.         //i代表数字数组下标  
  287.         //j代表字符数组下标  
  288.         output[i] = (input[j]) |    
  289.             (input[j+1] << 8) |    
  290.             (input[j+2] << 16) |    
  291.             (input[j+3] << 24);    
  292.         i++;    
  293.         j+=4;     
  294.     }    
  295. }    
  296.   
  297. /************************************************************** 
  298. * 函数功能:对512位的block数据进行加密,并把加密结果存入state数组中 
  299. * 对512位信息(即block字符数组)进行一次处理,每次处理包括四轮 
  300. *state[4]:md5结构中的state[4],用于保存对512bits信息加密的中间结果或者最终结果 
  301. * block[64]:欲加密的512bits信息或其中间数据 
  302. ***************************************************************/  
  303. void MD5Transform(unsigned int state[4],unsigned char block[64])    
  304. {    
  305.     //a b c d继承上一个加密的结果,所以其具有继承性  
  306.     unsigned int a = state[0];    
  307.     unsigned int b = state[1];    
  308.     unsigned int c = state[2];    
  309.     unsigned int d = state[3];    
  310.       
  311.     //这里只需用到16个,我把原来的unsiged int x[64]  改为了 x[16]  
  312.     unsigned int x[16];    
  313.       
  314.     //把字符转化成数字,便于运算  
  315.     MD5Decode(x,block,64);    
  316.       
  317.   
  318.     //具体函数方式固定,不再赘述  
  319.   
  320.     /*************第一轮******************/  
  321.     FF(a, b, c, d, x[ 0], 7, 0xd76aa478);     
  322.     FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);     
  323.     FF(c, d, a, b, x[ 2], 17, 0x242070db);     
  324.     FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);     
  325.       
  326.     FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);     
  327.     FF(d, a, b, c, x[ 5], 12, 0x4787c62a);     
  328.     FF(c, d, a, b, x[ 6], 17, 0xa8304613);     
  329.     FF(b, c, d, a, x[ 7], 22, 0xfd469501);     
  330.       
  331.     FF(a, b, c, d, x[ 8], 7, 0x698098d8);     
  332.     FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);     
  333.     FF(c, d, a, b, x[10], 17, 0xffff5bb1);     
  334.     FF(b, c, d, a, x[11], 22, 0x895cd7be);     
  335.       
  336.     FF(a, b, c, d, x[12], 7, 0x6b901122);     
  337.     FF(d, a, b, c, x[13], 12, 0xfd987193);     
  338.     FF(c, d, a, b, x[14], 17, 0xa679438e);     
  339.     FF(b, c, d, a, x[15], 22, 0x49b40821);     
  340.     
  341.         
  342.     /*************第二轮*****************/  
  343.     GG(a, b, c, d, x[ 1], 5, 0xf61e2562);     
  344.     GG(d, a, b, c, x[ 6], 9, 0xc040b340);     
  345.     GG(c, d, a, b, x[11], 14, 0x265e5a51);     
  346.     GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);     
  347.       
  348.     GG(a, b, c, d, x[ 5], 5, 0xd62f105d);     
  349.     GG(d, a, b, c, x[10], 9,  0x2441453);     
  350.     GG(c, d, a, b, x[15], 14, 0xd8a1e681);     
  351.     GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);     
  352.       
  353.     GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);     
  354.     GG(d, a, b, c, x[14], 9, 0xc33707d6);     
  355.     GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);     
  356.     GG(b, c, d, a, x[ 8], 20, 0x455a14ed);     
  357.       
  358.     GG(a, b, c, d, x[13], 5, 0xa9e3e905);     
  359.     GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);     
  360.     GG(c, d, a, b, x[ 7], 14, 0x676f02d9);     
  361.     GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);     
  362.     
  363.         
  364.     /*************第三轮*****************/  
  365.     HH(a, b, c, d, x[ 5], 4, 0xfffa3942);     
  366.     HH(d, a, b, c, x[ 8], 11, 0x8771f681);     
  367.     HH(c, d, a, b, x[11], 16, 0x6d9d6122);     
  368.     HH(b, c, d, a, x[14], 23, 0xfde5380c);     
  369.       
  370.     HH(a, b, c, d, x[ 1], 4, 0xa4beea44);     
  371.     HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);     
  372.     HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);     
  373.     HH(b, c, d, a, x[10], 23, 0xbebfbc70);     
  374.       
  375.     HH(a, b, c, d, x[13], 4, 0x289b7ec6);     
  376.     HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);     
  377.     HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);     
  378.     HH(b, c, d, a, x[ 6], 23,  0x4881d05);     
  379.       
  380.     HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);     
  381.     HH(d, a, b, c, x[12], 11, 0xe6db99e5);     
  382.     HH(c, d, a, b, x[15], 16, 0x1fa27cf8);     
  383.     HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);     
  384.     
  385.         
  386.       
  387.     /*************第四轮******************/  
  388.     II(a, b, c, d, x[ 0], 6, 0xf4292244);     
  389.     II(d, a, b, c, x[ 7], 10, 0x432aff97);     
  390.     II(c, d, a, b, x[14], 15, 0xab9423a7);     
  391.     II(b, c, d, a, x[ 5], 21, 0xfc93a039);     
  392.       
  393.     II(a, b, c, d, x[12], 6, 0x655b59c3);     
  394.     II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);     
  395.     II(c, d, a, b, x[10], 15, 0xffeff47d);     
  396.     II(b, c, d, a, x[ 1], 21, 0x85845dd1);     
  397.       
  398.     II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);     
  399.     II(d, a, b, c, x[15], 10, 0xfe2ce6e0);     
  400.     II(c, d, a, b, x[ 6], 15, 0xa3014314);     
  401.     II(b, c, d, a, x[13], 21, 0x4e0811a1);     
  402.       
  403.     II(a, b, c, d, x[ 4], 6, 0xf7537e82);     
  404.     II(d, a, b, c, x[11], 10, 0xbd3af235);     
  405.     II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);     
  406.     II(b, c, d, a, x[ 9], 21, 0xeb86d391);     
  407.       
  408.   
  409.     //更换原来的结果  
  410.     state[0] += a;    
  411.     state[1] += b;    
  412.     state[2] += c;    
  413.     state[3] += d;    
  414. }    
  415.   
  416.   
  417.   
  418.   
  419.   
  420.   
  421. int main(int argc, char *argv[])    
  422. {    
  423.     MD5_CTX md5;  //定义一个MD5 text  
  424.     MD5Init(&md5);//初始化             
  425.     int i;    
  426.     unsigned char encrypt[] ="admin";//要加密内容  
  427.     //21232f297a57a5a743894a0e4a801fc3    
  428.     unsigned char decrypt[16]; //加密结果       
  429.     MD5Update(&md5,encrypt,strlen((char *)encrypt));//进行初步分组加密    
  430.     MD5Final(&md5,decrypt);   //进行后序的补足,并加密   
  431.       
  432.     printf("加密前:%s\n加密后16位:",encrypt);    
  433.     for(i=4;i<12;i++)    
  434.     {    
  435.         printf("%02x",decrypt[i]);  //02x前需要加上 %    
  436.     }    
  437.          
  438.     printf("\n加密前:%s\n加密后32位:",encrypt);    
  439.     for(i=0;i<16;i++)    
  440.     {    
  441.         printf("%02x",decrypt[i]);  //02x前需要加上 %    
  442.     }    
  443.    
  444.     
  445.     return 0;    
  446. }    
/*************************************************************************
	> File Name: md5_1.cpp
	> Author:chudongfang 
	> Mail:1149669942@qq.com 
	> Created Time: 2016年06月22日 星期三 16时12分30秒
 ************************************************************************/
 
#include <string.h>
#include <math.h>
#include <stdio.h>
 

/***********************************
 * 非线性函数
 * (&是与,|是或,~是非,^是异或) 
 * 
 * 这些函数是这样设计的:
 *   如果X、Y和Z的对应位是独立和均匀的,
 *   那么结果的每一位也应是独立和均匀的。 
 * 
 * 函数F是按逐位方式操作:如果X,那么Y,否则Z。
 * 函数H是逐位奇偶操作符
 **********************************/
#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))  


/**************************************
 *向右环移n个单位
 * ************************************/
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))  




/****************************************************
 * 每次操作对a,b,c和d中的其中三个作一次非线性函数运算
 *  F(b,c,d)   G(b,c,d)   H(b,c,d)   I(b,c,d)
 *
 * 然后将所得结果加上 第四个变量(a),
 * F(b,c,d)+a
 *
 * 文本的一个子分组(x)
 * F(b,c,d)+a+x
 * 
 * 和一个常数(ac)。
 * F(b,c,d)+a+x+ac
 *
 * 再将所得结果向右环移一个不定的数(s),
 * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )
 * 
 * 并加上a,b,c或d中之一(b)。
 * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b
 * 
 * 最后用该结果取代a,b,c或d中之一(a)。
 * a=ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b
 * 
 * ***************************************************/


#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; }





//储存一个MD5 text信息 
typedef struct  
{  
    unsigned int count[2];    
    //记录当前状态,其数据位数   
    
    unsigned int state[4];    
    //4个数,一共32位 记录用于保存对512bits信息加密的中间结果或者最终结果  
    
    unsigned char buffer[64];
    //一共64字节,512位      
}MD5_CTX;  
  


//第一位1 其后若干个0,用于MD5Final函数时的补足
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);  

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);  
  




/************************
 * 函数功能:初始化一个MD5 text
 * 函数参数:MD5 text 指针
 * ***********************/
//初始化
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;  
}  


/************************************************
 * 函数功能:对一个MD5 text,把输入的数据进行分组,并进行加密
 * 未用到的数据把其储存在MD5 text中。
 *
 * 参数分析:
 * MD5_CTX *context       :一个MD5 text   
 * unsigned char *input   :新添加的数据  
 * unsigned int inputlen  :新添加数据的长度(字节)
 *
 ***********************************************/

void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)  
{  
    unsigned int i = 0,index = 0,partlen = 0;  
    
    //index:当前状态的位数对64取余,其单位是字节
    //也可以写作:  index=(context->count[0]/8)%64
    index = (context->count[0] >> 3) & 0x3F;  
    
    //partlen:可以补齐64字节的字节数
    partlen = 64 - index;  
    
    //下面代码是解决一个unsignde int 无法储存极大数据导致溢出的问题
    //当前位数加上新添加的位数,由于inputlen是以字节为单位,所以其转换为位数
    //相当于context->count[0] += inputlen*8;  
    context->count[0] += inputlen << 3;  
   
    //当其出现溢出的情况时,通过以下操作把两个16位的数连在一块,生成一个
    //32位的二进制数串,从而扩大其储存范围
    if(context->count[0] < (inputlen << 3))  
        context->count[1]++;
    
    //该语句可替换为 context->count[1]+=(inputlen<<3)>>32;
    //便于理解
    context->count[1] += inputlen >> 29;  
    
    //当其输入字节数的大于其可以补足64字节的字节数,进行补足
    if(inputlen >= partlen)  
    {  
        //向buffer中补足partlen个字节,使其到达64字节
        memcpy(&context->buffer[index],input,partlen);
        
        //buffer达到64字节512位,则把其作为一组进行运算
        MD5Transform(context->state,context->buffer);  
        
        //如果输入的数据还可以组成多个64字节,则把其可以组成
        //的作为若干组进行运算
        for(i = partlen;i+64 <= inputlen;i+=64)  
            MD5Transform(context->state,&input[i]);  
        
        //恢复0值,照应 下面 把输入 剩余字节(不能组成64字节组) 储存的操作
        index = 0;          
    }   
    //否则,把输入的数据按顺序放在原来数据后面
    else  
    {  
        i = 0;  
    }  

    //放置剩余数据
    memcpy(&context->buffer[index],&input[i],inputlen-i);  
}  




/*************************************************
 * 函数功能:对数据进行补足,并加入数据位数信息,并进一步加密
 * 
 * 参数分析:
 * MD5_CTX *context          :一个MD5 text
 * unsigned char digest[16]  :储存加密结果的数组
 *************************************************/

void MD5Final(MD5_CTX *context,unsigned char digest[16])  
{  
    unsigned int index = 0,padlen = 0;  
    
    //bits: 8个字节,64位
    unsigned char bits[8];  
    
    //index:对64取余结果
    index = (context->count[0] >> 3) & 0x3F;  
    //因为要填充满足使其位长对512求余的结果等于448(56位)
    //所以当其所剩余的数小于56字节,则填充56-index字节,
    //否则填充120-index字节
    //这里padlen代表其所需填充的字节
    padlen = (index < 56)?(56-index):(120-index);  
    
    //然后,在这个结果后面附加一个以64位二进制表示的填充前数据长度。
    //把填充前数据数据长度转换后放到bit字符数组中
    MD5Encode(bits,context->count,8);
    
    //根据已经存储好的数组PADDING,在信息的后面填充一个1和无数个0,
    //直到满足上面的条件时才停止用0对信息的填充
    //其填充后进行了一系列的加密操作,其定剩余48个字节
    MD5Update(context,PADDING,padlen);  

    //在最后添加进8个字节的数据长度信息,最后凑成一组,进行一次加密处理
    MD5Update(context,bits,8);  
    
    //把最终得到的加密信息变成字符输出,共16字节
    MD5Encode(digest,context->state,16);  
}  




/**********************************************************
 * 函数功能:利用位操作,按1->4方式把数字分解成字符
 *
 * 参数分析:
 * unsigned char  *output :输出的字符的数组
 * unsigned int   *input  :输入数字的数组
 * unsigned int   len     : 输入数字数组的长度(单位:位) 
 * *********************************************************/

void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)  
{  
    unsigned int i = 0,j = 0;  
    while(j < len)  
    {  
        //这里& 0xFF为取后8位
        //i代表数字数组下标
        //j代表字符数组下标
        //把数字的8、8-16、16-24、24-32分别赋值给字符
        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;  
    }  
}  




/**********************************************************
 * 函数功能:利用位操作,按4->1方式把字符合成数字
 *
 * 参数分析:
 * unsigned int  *output :输出的数字的数组
 * unsigned char *input  :输入字符的数组
 * unsigned int  len     : 输入字符的长度 (单位:位)
 * *********************************************************/

void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)  
{  
    unsigned int i = 0,j = 0;  
    while(j < len)  
    {  
        //利用位操作,把四个单位为1字节的字符,合成一个单位为4字节的数字
        //因为FF GG HH II和非线性函数都只能对数字进行处理
        //第一个字符占前8位,第二个占8-16位,第三个占16-24位,第四个占
        //24-32位。
        //i代表数字数组下标
        //j代表字符数组下标
        output[i] = (input[j]) |  
            (input[j+1] << 8) |  
            (input[j+2] << 16) |  
            (input[j+3] << 24);  
        i++;  
        j+=4;   
    }  
}  

/**************************************************************
* 函数功能:对512位的block数据进行加密,并把加密结果存入state数组中
* 对512位信息(即block字符数组)进行一次处理,每次处理包括四轮
*state[4]:md5结构中的state[4],用于保存对512bits信息加密的中间结果或者最终结果
* block[64]:欲加密的512bits信息或其中间数据
***************************************************************/
void MD5Transform(unsigned int state[4],unsigned char block[64])  
{  
    //a b c d继承上一个加密的结果,所以其具有继承性
    unsigned int a = state[0];  
    unsigned int b = state[1];  
    unsigned int c = state[2];  
    unsigned int d = state[3];  
    
    //这里只需用到16个,我把原来的unsiged int x[64]  改为了 x[16]
    unsigned int x[16];  
    
    //把字符转化成数字,便于运算
    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;  
}  






int main(int argc, char *argv[])  
{  
    MD5_CTX md5;  //定义一个MD5 text
    MD5Init(&md5);//初始化           
    int i;  
    unsigned char encrypt[] ="admin";//要加密内容
    //21232f297a57a5a743894a0e4a801fc3  
    unsigned char decrypt[16]; //加密结果     
    MD5Update(&md5,encrypt,strlen((char *)encrypt));//进行初步分组加密  
    MD5Final(&md5,decrypt);   //进行后序的补足,并加密 
    
    printf("加密前:%s\n加密后16位:",encrypt);  
    for(i=4;i<12;i++)  
    {  
        printf("%02x",decrypt[i]);  //02x前需要加上 %  
    }  
       
    printf("\n加密前:%s\n加密后32位:",encrypt);  
    for(i=0;i<16;i++)  
    {  
        printf("%02x",decrypt[i]);  //02x前需要加上 %  
    }  
 
  
    return 0;  
}  



看过代码,相信已经有了初步的理解。这里我再根据我的理解来总结一下:

1.首先其核心部分为这九个函数:

  1. #define F(x,y,z) ((x & y) | (~x & z))    
  2. #define G(x,y,z) ((x & z) | (y & ~z))    
  3. #define H(x,y,z) (x^y^z)    
  4. #define I(x,y,z) (y ^ (x | ~z))    
#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))  

  1. #define FF(a,b,c,d,x,s,ac) { a += F(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  2. #define GG(a,b,c,d,x,s,ac) { a += G(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  3. #define HH(a,b,c,d,x,s,ac) { a += H(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  4. #define II(a,b,c,d,x,s,ac) { a += I(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
#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; }

  1. #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))    
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))  

可以说这九个函数和一些固定参数组成了加密核心,我们把它视为一个模块,

这个模块输入为4个unsigned int 类型数字和x[16]   经过一系列位运算,输出 4个unsinged int 类型数字

而且其有连续性特点 ,即其上一次的加密结果会在本此加密中作为初始值进行加密,

外加了由 输入数据 转化成的x[]数组,参入到其中。

实现这个功能是由其实现:

  1. <pre name="code" class="cpp" style="font-size: 18px;">void MD5Transform(unsigned int state[4],unsigned char block[64]);    
<pre name="code" class="cpp" style="font-size: 18px;">void MD5Transform(unsigned int state[4],unsigned char block[64]);  
 

2.我们现在只需对数据进行处理,处理成与其所输入类型相同的数据。

根据其输入特征,我们需要512位 (64个字节)的数据,所以我们以512位为一组,

下面需要做的就是进行分组和最后加入长度信息的补全,

分组由其实现:

  1. void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);    
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);  
加入长度信息的补全由其实现:

  1. void MD5Final(MD5_CTX *context,unsigned char digest[16]);    
void MD5Final(MD5_CTX *context,unsigned char digest[16]);  


由于数据为unsinged char类型,所以在这个过程中肯定会涉及到unsinged char 和 unsinged int 类型的转化。


unsinged char ->unsinged int由其实现:

  1. void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)    
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)  


unsinged int ->unsinged char由其实现:

  1. void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)    
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)  


下面我自己改了一下,改成一个MD5加密器,原理完全一样,只是做了小小的修改:


  1. /************************************************************************* 
  2.     > File Name: md5_1.cpp 
  3.     > Author:chudongfang  
  4.     > Mail:1149669942@qq.com  
  5.     > Created Time: 2016年06月22日 星期三 16时12分30秒 
  6.  ************************************************************************/  
  7.    
  8. #include <string.h>  
  9. #include <math.h>  
  10. #include <stdio.h>  
  11.    
  12.   
  13. /*********************************** 
  14.  * 非线性函数 
  15.  * (&是与,|是或,~是非,^是异或)  
  16.  *  
  17.  * 这些函数是这样设计的: 
  18.  *   如果X、Y和Z的对应位是独立和均匀的, 
  19.  *   那么结果的每一位也应是独立和均匀的。  
  20.  *  
  21.  * 函数F是按逐位方式操作:如果X,那么Y,否则Z。 
  22.  * 函数H是逐位奇偶操作符 
  23.  **********************************/  
  24. #define F(x,y,z) ((x & y) | (~x & z))    
  25. #define G(x,y,z) ((x & z) | (y & ~z))    
  26. #define H(x,y,z) (x^y^z)    
  27. #define I(x,y,z) (y ^ (x | ~z))    
  28.   
  29.   
  30. /************************************** 
  31.  *向右环移n个单位 
  32.  * ************************************/  
  33. #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))    
  34.   
  35.   
  36.   
  37.   
  38. /**************************************************** 
  39.  * 每次操作对a,b,c和d中的其中三个作一次非线性函数运算 
  40.  *  F(b,c,d)   G(b,c,d)   H(b,c,d)   I(b,c,d) 
  41.  * 
  42.  * 然后将所得结果加上 第四个变量(a), 
  43.  * F(b,c,d)+a 
  44.  * 
  45.  * 文本的一个子分组(x) 
  46.  * F(b,c,d)+a+x 
  47.  *  
  48.  * 和一个常数(ac)。 
  49.  * F(b,c,d)+a+x+ac 
  50.  * 
  51.  * 再将所得结果向右环移一个不定的数(s), 
  52.  * ROTATE_LEFT( F(b,c,d)+a+x+ac , s ) 
  53.  *  
  54.  * 并加上a,b,c或d中之一(b)。 
  55.  * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b 
  56.  *  
  57.  * 最后用该结果取代a,b,c或d中之一(a)。 
  58.  * a=ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b 
  59.  *  
  60.  * ***************************************************/  
  61.   
  62.   
  63. #define FF(a,b,c,d,x,s,ac) { a += F(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  64. #define GG(a,b,c,d,x,s,ac) { a += G(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  65. #define HH(a,b,c,d,x,s,ac) { a += H(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  66. #define II(a,b,c,d,x,s,ac) { a += I(b,c,d) + x + ac;  a = ROTATE_LEFT(a,s); a += b; }  
  67.   
  68.   
  69.   
  70.   
  71.   
  72. //储存一个MD5 text信息   
  73. typedef struct    
  74. {    
  75.     unsigned int count[2];      
  76.     //记录当前状态,其数据位数     
  77.       
  78.     unsigned int state[4];      
  79.     //4个数,一共32位 记录用于保存对512bits信息加密的中间结果或者最终结果    
  80.       
  81.     unsigned char buffer[64];  
  82.     //一共64字节,512位        
  83. }MD5_CTX;    
  84.     
  85.   
  86.   
  87. //第一位1 其后若干个0,用于MD5Final函数时的补足  
  88. unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  89. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  90. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    
  91. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};    
  92.     
  93.   
  94.   
  95. //函数声明区,每个函数在下面都有较详细说明,这里不再赘述  
  96.   
  97. void MD5Init(MD5_CTX *context);    
  98.   
  99. void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);    
  100.   
  101. void MD5Final(MD5_CTX *context,unsigned char digest[16]);    
  102.   
  103. void MD5Transform(unsigned int state[4],unsigned char block[64]);    
  104.   
  105. void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);    
  106.   
  107. void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);    
  108.     
  109. void MD5();  
  110.   
  111.   
  112.   
  113. /************************ 
  114.  * 函数功能:初始化一个MD5 text 
  115.  * 函数参数:MD5 text 指针 
  116.  * ***********************/  
  117. //初始化  
  118. void MD5Init(MD5_CTX *context)    
  119. {    
  120.     context->count[0] = 0;    
  121.     context->count[1] = 0;     
  122.     //分别赋固定值    
  123.     context->state[0] = 0x67452301;  
  124.     context->state[1] = 0xEFCDAB89;    
  125.     context->state[2] = 0x98BADCFE;    
  126.     context->state[3] = 0x10325476;    
  127. }    
  128.   
  129.   
  130. /************************************************ 
  131.  * 函数功能:对一个MD5 text,把输入的数据进行分组,并进行加密 
  132.  * 未用到的数据把其储存在MD5 text中。 
  133.  * 
  134.  * 参数分析: 
  135.  * MD5_CTX *context       :一个MD5 text    
  136.  * unsigned char *input   :新添加的数据   
  137.  * unsigned int inputlen  :新添加数据的长度(字节) 
  138.  * 
  139.  ***********************************************/  
  140.   
  141. void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)    
  142. {    
  143.     unsigned int i = 0,index = 0,partlen = 0;    
  144.       
  145.     //index:当前状态的位数对64取余,其单位是字节  
  146.     //也可以写作:  index=(context->count[0]/8)%64  
  147.     index = (context->count[0] >> 3) & 0x3F;    
  148.       
  149.     //partlen:可以补齐64字节的字节数  
  150.     partlen = 64 - index;    
  151.       
  152.     //下面代码是解决一个unsignde int 无法储存极大数据导致溢出的问题  
  153.     //当前位数加上新添加的位数,由于inputlen是以字节为单位,所以其转换为位数  
  154.     //相当于context->count[0] += inputlen*8;    
  155.     context->count[0] += inputlen << 3;    
  156.      
  157.     //当其出现溢出的情况时,通过以下操作把两个16位的数连在一块,生成一个  
  158.     //32位的二进制数串,从而扩大其储存范围  
  159.     if(context->count[0] < (inputlen << 3))    
  160.         context->count[1]++;  
  161.       
  162.     //该语句可替换为 context->count[1]+=(inputlen<<3)>>32;  
  163.     //便于理解  
  164.     context->count[1] += inputlen >> 29;    
  165.       
  166.     //当其输入字节数的大于其可以补足64字节的字节数,进行补足  
  167.     if(inputlen >= partlen)    
  168.     {    
  169.         //向buffer中补足partlen个字节,使其到达64字节  
  170.         memcpy(&context->buffer[index],input,partlen);  
  171.           
  172.         //buffer达到64字节512位,则把其作为一组进行运算  
  173.         MD5Transform(context->state,context->buffer);    
  174.           
  175.         //如果输入的数据还可以组成多个64字节,则把其可以组成  
  176.         //的作为若干组进行运算  
  177.         for(i = partlen;i+64 <= inputlen;i+=64)    
  178.             MD5Transform(context->state,&input[i]);    
  179.           
  180.         //恢复0值,照应 下面 把输入 剩余字节(不能组成64字节组) 储存的操作  
  181.         index = 0;            
  182.     }     
  183.     //否则,把输入的数据按顺序放在原来数据后面  
  184.     else    
  185.     {    
  186.         i = 0;    
  187.     }    
  188.   
  189.     //放置剩余数据  
  190.     memcpy(&context->buffer[index],&input[i],inputlen-i);    
  191. }    
  192.   
  193.   
  194.   
  195.   
  196. /************************************************* 
  197.  * 函数功能:对数据进行补足,并加入数据位数信息,并进一步加密 
  198.  *  
  199.  * 参数分析: 
  200.  * MD5_CTX *context          :一个MD5 text 
  201.  * unsigned char digest[16]  :储存加密结果的数组 
  202.  *************************************************/  
  203.   
  204. void MD5Final(MD5_CTX *context,unsigned char digest[16])    
  205. {    
  206.     unsigned int index = 0,padlen = 0;    
  207.       
  208.     //bits: 8个字节,64位  
  209.     unsigned char bits[8];    
  210.       
  211.     //index:对64取余结果  
  212.     index = (context->count[0] >> 3) & 0x3F;    
  213.     //因为要填充满足使其位长对512求余的结果等于448(56位)  
  214.     //所以当其所剩余的数小于56字节,则填充56-index字节,  
  215.     //否则填充120-index字节  
  216.     //这里padlen代表其所需填充的字节  
  217.     padlen = (index < 56)?(56-index):(120-index);    
  218.       
  219.     //然后,在这个结果后面附加一个以64位二进制表示的填充前数据长度。  
  220.     //把填充前数据数据长度转换后放到bit字符数组中  
  221.     MD5Encode(bits,context->count,8);  
  222.       
  223.     //根据已经存储好的数组PADDING,在信息的后面填充一个1和无数个0,  
  224.     //直到满足上面的条件时才停止用0对信息的填充  
  225.     //其填充后进行了一系列的加密操作,其定剩余48个字节  
  226.     MD5Update(context,PADDING,padlen);    
  227.   
  228.     //在最后添加进8个字节的数据长度信息,最后凑成一组,进行一次加密处理  
  229.     MD5Update(context,bits,8);    
  230.       
  231.     //把最终得到的加密信息变成字符输出,共16字节  
  232.     MD5Encode(digest,context->state,16);    
  233. }    
  234.   
  235.   
  236.   
  237.   
  238. /********************************************************** 
  239.  * 函数功能:利用位操作,按1->4方式把数字分解成字符 
  240.  * 
  241.  * 参数分析: 
  242.  * unsigned char  *output :输出的字符的数组 
  243.  * unsigned int   *input  :输入数字的数组 
  244.  * unsigned int   len     : 输入数字数组的长度(单位:位)  
  245.  * *********************************************************/  
  246.   
  247. void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)    
  248. {    
  249.     unsigned int i = 0,j = 0;    
  250.     while(j < len)    
  251.     {    
  252.         //这里& 0xFF为取后8位  
  253.         //i代表数字数组下标  
  254.         //j代表字符数组下标  
  255.         //把数字的8、8-16、16-24、24-32分别赋值给字符  
  256.         output[j] = input[i] & 0xFF;      
  257.         output[j+1] = (input[i] >> 8) & 0xFF;    
  258.         output[j+2] = (input[i] >> 16) & 0xFF;    
  259.         output[j+3] = (input[i] >> 24) & 0xFF;    
  260.         i++;    
  261.         j+=4;    
  262.     }    
  263. }    
  264.   
  265.   
  266.   
  267.   
  268. /********************************************************** 
  269.  * 函数功能:利用位操作,按4->1方式把字符合成数字 
  270.  * 
  271.  * 参数分析: 
  272.  * unsigned int  *output :输出的数字的数组 
  273.  * unsigned char *input  :输入字符的数组 
  274.  * unsigned int  len     : 输入字符的长度 (单位:位) 
  275.  * *********************************************************/  
  276.   
  277. void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)    
  278. {    
  279.     unsigned int i = 0,j = 0;    
  280.     while(j < len)    
  281.     {    
  282.         //利用位操作,把四个单位为1字节的字符,合成一个单位为4字节的数字  
  283.         //因为FF GG HH II和非线性函数都只能对数字进行处理  
  284.         //第一个字符占前8位,第二个占8-16位,第三个占16-24位,第四个占  
  285.         //24-32位。  
  286.         //i代表数字数组下标  
  287.         //j代表字符数组下标  
  288.         output[i] = (input[j]) |    
  289.             (input[j+1] << 8) |    
  290.             (input[j+2] << 16) |    
  291.             (input[j+3] << 24);    
  292.         i++;    
  293.         j+=4;     
  294.     }    
  295. }    
  296.   
  297. /************************************************************** 
  298. * 函数功能:对512位的block数据进行加密,并把加密结果存入state数组中 
  299. * 对512位信息(即block字符数组)进行一次处理,每次处理包括四轮 
  300. *state[4]:md5结构中的state[4],用于保存对512bits信息加密的中间结果或者最终结果 
  301. * block[64]:欲加密的512bits信息或其中间数据 
  302. ***************************************************************/  
  303. void MD5Transform(unsigned int state[4],unsigned char block[64])    
  304. {    
  305.     //a b c d继承上一个加密的结果,所以其具有继承性  
  306.     unsigned int a = state[0];    
  307.     unsigned int b = state[1];    
  308.     unsigned int c = state[2];    
  309.     unsigned int d = state[3];    
  310.       
  311.     //这里只需用到16个,我把原来的unsiged int x[64]  改为了 x[16]  
  312.     unsigned int x[16];    
  313.       
  314.     //把字符转化成数字,便于运算  
  315.     MD5Decode(x,block,64);    
  316.       
  317.   
  318.     //具体函数方式固定,不再赘述  
  319.   
  320.     /*************第一轮******************/  
  321.     FF(a, b, c, d, x[ 0], 7, 0xd76aa478);     
  322.     FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);     
  323.     FF(c, d, a, b, x[ 2], 17, 0x242070db);     
  324.     FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);     
  325.       
  326.     FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);     
  327.     FF(d, a, b, c, x[ 5], 12, 0x4787c62a);     
  328.     FF(c, d, a, b, x[ 6], 17, 0xa8304613);     
  329.     FF(b, c, d, a, x[ 7], 22, 0xfd469501);     
  330.       
  331.     FF(a, b, c, d, x[ 8], 7, 0x698098d8);     
  332.     FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);     
  333.     FF(c, d, a, b, x[10], 17, 0xffff5bb1);     
  334.     FF(b, c, d, a, x[11], 22, 0x895cd7be);     
  335.       
  336.     FF(a, b, c, d, x[12], 7, 0x6b901122);     
  337.     FF(d, a, b, c, x[13], 12, 0xfd987193);     
  338.     FF(c, d, a, b, x[14], 17, 0xa679438e);     
  339.     FF(b, c, d, a, x[15], 22, 0x49b40821);     
  340.     
  341.         
  342.     /*************第二轮*****************/  
  343.     GG(a, b, c, d, x[ 1], 5, 0xf61e2562);     
  344.     GG(d, a, b, c, x[ 6], 9, 0xc040b340);     
  345.     GG(c, d, a, b, x[11], 14, 0x265e5a51);     
  346.     GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);     
  347.       
  348.     GG(a, b, c, d, x[ 5], 5, 0xd62f105d);     
  349.     GG(d, a, b, c, x[10], 9,  0x2441453);     
  350.     GG(c, d, a, b, x[15], 14, 0xd8a1e681);     
  351.     GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);     
  352.       
  353.     GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);     
  354.     GG(d, a, b, c, x[14], 9, 0xc33707d6);     
  355.     GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);     
  356.     GG(b, c, d, a, x[ 8], 20, 0x455a14ed);     
  357.       
  358.     GG(a, b, c, d, x[13], 5, 0xa9e3e905);     
  359.     GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);     
  360.     GG(c, d, a, b, x[ 7], 14, 0x676f02d9);     
  361.     GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);     
  362.     
  363.         
  364.     /*************第三轮*****************/  
  365.     HH(a, b, c, d, x[ 5], 4, 0xfffa3942);     
  366.     HH(d, a, b, c, x[ 8], 11, 0x8771f681);     
  367.     HH(c, d, a, b, x[11], 16, 0x6d9d6122);     
  368.     HH(b, c, d, a, x[14], 23, 0xfde5380c);     
  369.       
  370.     HH(a, b, c, d, x[ 1], 4, 0xa4beea44);     
  371.     HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);     
  372.     HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);     
  373.     HH(b, c, d, a, x[10], 23, 0xbebfbc70);     
  374.       
  375.     HH(a, b, c, d, x[13], 4, 0x289b7ec6);     
  376.     HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);     
  377.     HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);     
  378.     HH(b, c, d, a, x[ 6], 23,  0x4881d05);     
  379.       
  380.     HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);     
  381.     HH(d, a, b, c, x[12], 11, 0xe6db99e5);     
  382.     HH(c, d, a, b, x[15], 16, 0x1fa27cf8);     
  383.     HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);     
  384.     
  385.         
  386.       
  387.     /*************第四轮******************/  
  388.     II(a, b, c, d, x[ 0], 6, 0xf4292244);     
  389.     II(d, a, b, c, x[ 7], 10, 0x432aff97);     
  390.     II(c, d, a, b, x[14], 15, 0xab9423a7);     
  391.     II(b, c, d, a, x[ 5], 21, 0xfc93a039);     
  392.       
  393.     II(a, b, c, d, x[12], 6, 0x655b59c3);     
  394.     II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);     
  395.     II(c, d, a, b, x[10], 15, 0xffeff47d);     
  396.     II(b, c, d, a, x[ 1], 21, 0x85845dd1);     
  397.       
  398.     II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);     
  399.     II(d, a, b, c, x[15], 10, 0xfe2ce6e0);     
  400.     II(c, d, a, b, x[ 6], 15, 0xa3014314);     
  401.     II(b, c, d, a, x[13], 21, 0x4e0811a1);     
  402.       
  403.     II(a, b, c, d, x[ 4], 6, 0xf7537e82);     
  404.     II(d, a, b, c, x[11], 10, 0xbd3af235);     
  405.     II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);     
  406.     II(b, c, d, a, x[ 9], 21, 0xeb86d391);     
  407.       
  408.   
  409.     //更换原来的结果  
  410.     state[0] += a;    
  411.     state[1] += b;    
  412.     state[2] += c;    
  413.     state[3] += d;    
  414. }    
  415.   
  416.   
  417. void MD5()  
  418. {  
  419.     MD5_CTX md5;  //定义一个MD5 text  
  420.     MD5Init(&md5);//初始化           
  421.     unsigned char encrypt[1000];//要加密内容  
  422.     unsigned char decrypt[16]; //加密结果     
  423.      
  424.     printf("请输入要加密的信息:");  
  425.     scanf("%s",encrypt);  
  426.       
  427.     MD5Update(&md5,encrypt,strlen((char *)encrypt));//进行初步分组加密    
  428.     MD5Final(&md5,decrypt);   //进行后序的补足,并加密   
  429.   
  430.     printf("\n加密前:%s\n加密后16位:",encrypt);  
  431.     for(int i=4;i<12;i++)    
  432.         printf("%02x",decrypt[i]);  //02x前需要加上 %   
  433.       
  434.     printf("\n加密后:%s\n加密后32位:",encrypt);    
  435.     for(int i=0;i<16;i++)    
  436.         printf("%02x",decrypt[i]);  //02x前需要加上 %    
  437.    
  438.       
  439. }  
  440.   
  441.   
  442.   
  443.   
  444.   
  445.   
  446. int main(int argc, char *argv[])    
  447. {     
  448.     int chioce;  
  449.     do  
  450.     {  
  451.         printf("\n\t\t**********MD5加密器××********\n");  
  452.         printf("\t\t*        1.数据加密           *\n");  
  453.         printf("\t\t*        0.退出               *\n");  
  454.         printf("\t\t*******************************\n");  
  455.         printf("\t\t请选择:");  
  456.         scanf("%d",&chioce);  
  457.         switch(chioce)  
  458.         {    
  459.             case 1:  
  460.                 MD5();  
  461.                 break;  
  462.             default:  
  463.                 break;  
  464.         }  
  465.     }while(chioce!=0);  
  466.     return 0;   
  467. }    
/*************************************************************************
	> File Name: md5_1.cpp
	> Author:chudongfang 
	> Mail:1149669942@qq.com 
	> Created Time: 2016年06月22日 星期三 16时12分30秒
 ************************************************************************/
 
#include <string.h>
#include <math.h>
#include <stdio.h>
 

/***********************************
 * 非线性函数
 * (&是与,|是或,~是非,^是异或) 
 * 
 * 这些函数是这样设计的:
 *   如果X、Y和Z的对应位是独立和均匀的,
 *   那么结果的每一位也应是独立和均匀的。 
 * 
 * 函数F是按逐位方式操作:如果X,那么Y,否则Z。
 * 函数H是逐位奇偶操作符
 **********************************/
#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))  


/**************************************
 *向右环移n个单位
 * ************************************/
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))  




/****************************************************
 * 每次操作对a,b,c和d中的其中三个作一次非线性函数运算
 *  F(b,c,d)   G(b,c,d)   H(b,c,d)   I(b,c,d)
 *
 * 然后将所得结果加上 第四个变量(a),
 * F(b,c,d)+a
 *
 * 文本的一个子分组(x)
 * F(b,c,d)+a+x
 * 
 * 和一个常数(ac)。
 * F(b,c,d)+a+x+ac
 *
 * 再将所得结果向右环移一个不定的数(s),
 * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )
 * 
 * 并加上a,b,c或d中之一(b)。
 * ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b
 * 
 * 最后用该结果取代a,b,c或d中之一(a)。
 * a=ROTATE_LEFT( F(b,c,d)+a+x+ac , s )+b
 * 
 * ***************************************************/


#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; }





//储存一个MD5 text信息 
typedef struct  
{  
    unsigned int count[2];    
    //记录当前状态,其数据位数   
    
    unsigned int state[4];    
    //4个数,一共32位 记录用于保存对512bits信息加密的中间结果或者最终结果  
    
    unsigned char buffer[64];
    //一共64字节,512位      
}MD5_CTX;  
  


//第一位1 其后若干个0,用于MD5Final函数时的补足
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);  

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);  
  
void MD5();



/************************
 * 函数功能:初始化一个MD5 text
 * 函数参数:MD5 text 指针
 * ***********************/
//初始化
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;  
}  


/************************************************
 * 函数功能:对一个MD5 text,把输入的数据进行分组,并进行加密
 * 未用到的数据把其储存在MD5 text中。
 *
 * 参数分析:
 * MD5_CTX *context       :一个MD5 text   
 * unsigned char *input   :新添加的数据  
 * unsigned int inputlen  :新添加数据的长度(字节)
 *
 ***********************************************/

void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)  
{  
    unsigned int i = 0,index = 0,partlen = 0;  
    
    //index:当前状态的位数对64取余,其单位是字节
    //也可以写作:  index=(context->count[0]/8)%64
    index = (context->count[0] >> 3) & 0x3F;  
    
    //partlen:可以补齐64字节的字节数
    partlen = 64 - index;  
    
    //下面代码是解决一个unsignde int 无法储存极大数据导致溢出的问题
    //当前位数加上新添加的位数,由于inputlen是以字节为单位,所以其转换为位数
    //相当于context->count[0] += inputlen*8;  
    context->count[0] += inputlen << 3;  
   
    //当其出现溢出的情况时,通过以下操作把两个16位的数连在一块,生成一个
    //32位的二进制数串,从而扩大其储存范围
    if(context->count[0] < (inputlen << 3))  
        context->count[1]++;
    
    //该语句可替换为 context->count[1]+=(inputlen<<3)>>32;
    //便于理解
    context->count[1] += inputlen >> 29;  
    
    //当其输入字节数的大于其可以补足64字节的字节数,进行补足
    if(inputlen >= partlen)  
    {  
        //向buffer中补足partlen个字节,使其到达64字节
        memcpy(&context->buffer[index],input,partlen);
        
        //buffer达到64字节512位,则把其作为一组进行运算
        MD5Transform(context->state,context->buffer);  
        
        //如果输入的数据还可以组成多个64字节,则把其可以组成
        //的作为若干组进行运算
        for(i = partlen;i+64 <= inputlen;i+=64)  
            MD5Transform(context->state,&input[i]);  
        
        //恢复0值,照应 下面 把输入 剩余字节(不能组成64字节组) 储存的操作
        index = 0;          
    }   
    //否则,把输入的数据按顺序放在原来数据后面
    else  
    {  
        i = 0;  
    }  

    //放置剩余数据
    memcpy(&context->buffer[index],&input[i],inputlen-i);  
}  




/*************************************************
 * 函数功能:对数据进行补足,并加入数据位数信息,并进一步加密
 * 
 * 参数分析:
 * MD5_CTX *context          :一个MD5 text
 * unsigned char digest[16]  :储存加密结果的数组
 *************************************************/

void MD5Final(MD5_CTX *context,unsigned char digest[16])  
{  
    unsigned int index = 0,padlen = 0;  
    
    //bits: 8个字节,64位
    unsigned char bits[8];  
    
    //index:对64取余结果
    index = (context->count[0] >> 3) & 0x3F;  
    //因为要填充满足使其位长对512求余的结果等于448(56位)
    //所以当其所剩余的数小于56字节,则填充56-index字节,
    //否则填充120-index字节
    //这里padlen代表其所需填充的字节
    padlen = (index < 56)?(56-index):(120-index);  
    
    //然后,在这个结果后面附加一个以64位二进制表示的填充前数据长度。
    //把填充前数据数据长度转换后放到bit字符数组中
    MD5Encode(bits,context->count,8);
    
    //根据已经存储好的数组PADDING,在信息的后面填充一个1和无数个0,
    //直到满足上面的条件时才停止用0对信息的填充
    //其填充后进行了一系列的加密操作,其定剩余48个字节
    MD5Update(context,PADDING,padlen);  

    //在最后添加进8个字节的数据长度信息,最后凑成一组,进行一次加密处理
    MD5Update(context,bits,8);  
    
    //把最终得到的加密信息变成字符输出,共16字节
    MD5Encode(digest,context->state,16);  
}  




/**********************************************************
 * 函数功能:利用位操作,按1->4方式把数字分解成字符
 *
 * 参数分析:
 * unsigned char  *output :输出的字符的数组
 * unsigned int   *input  :输入数字的数组
 * unsigned int   len     : 输入数字数组的长度(单位:位) 
 * *********************************************************/

void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)  
{  
    unsigned int i = 0,j = 0;  
    while(j < len)  
    {  
        //这里& 0xFF为取后8位
        //i代表数字数组下标
        //j代表字符数组下标
        //把数字的8、8-16、16-24、24-32分别赋值给字符
        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;  
    }  
}  




/**********************************************************
 * 函数功能:利用位操作,按4->1方式把字符合成数字
 *
 * 参数分析:
 * unsigned int  *output :输出的数字的数组
 * unsigned char *input  :输入字符的数组
 * unsigned int  len     : 输入字符的长度 (单位:位)
 * *********************************************************/

void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)  
{  
    unsigned int i = 0,j = 0;  
    while(j < len)  
    {  
        //利用位操作,把四个单位为1字节的字符,合成一个单位为4字节的数字
        //因为FF GG HH II和非线性函数都只能对数字进行处理
        //第一个字符占前8位,第二个占8-16位,第三个占16-24位,第四个占
        //24-32位。
        //i代表数字数组下标
        //j代表字符数组下标
        output[i] = (input[j]) |  
            (input[j+1] << 8) |  
            (input[j+2] << 16) |  
            (input[j+3] << 24);  
        i++;  
        j+=4;   
    }  
}  

/**************************************************************
* 函数功能:对512位的block数据进行加密,并把加密结果存入state数组中
* 对512位信息(即block字符数组)进行一次处理,每次处理包括四轮
*state[4]:md5结构中的state[4],用于保存对512bits信息加密的中间结果或者最终结果
* block[64]:欲加密的512bits信息或其中间数据
***************************************************************/
void MD5Transform(unsigned int state[4],unsigned char block[64])  
{  
    //a b c d继承上一个加密的结果,所以其具有继承性
    unsigned int a = state[0];  
    unsigned int b = state[1];  
    unsigned int c = state[2];  
    unsigned int d = state[3];  
    
    //这里只需用到16个,我把原来的unsiged int x[64]  改为了 x[16]
    unsigned int x[16];  
    
    //把字符转化成数字,便于运算
    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;  
}  


void MD5()
{
	MD5_CTX md5;  //定义一个MD5 text
    MD5Init(&md5);//初始化         
	unsigned char encrypt[1000];//要加密内容
    unsigned char decrypt[16]; //加密结果   
   
    printf("请输入要加密的信息:");
    scanf("%s",encrypt);
    
    MD5Update(&md5,encrypt,strlen((char *)encrypt));//进行初步分组加密  
    MD5Final(&md5,decrypt);   //进行后序的补足,并加密 

    printf("\n加密前:%s\n加密后16位:",encrypt);
    for(int i=4;i<12;i++)  
        printf("%02x",decrypt[i]);  //02x前需要加上 % 
    
    printf("\n加密后:%s\n加密后32位:",encrypt);  
    for(int i=0;i<16;i++)  
        printf("%02x",decrypt[i]);  //02x前需要加上 %  
 
	
}






int main(int argc, char *argv[])  
{   
	int chioce;
	do
	{
    	printf("\n\t\t**********MD5加密器××********\n");
    	printf("\t\t*        1.数据加密           *\n");
    	printf("\t\t*        0.退出               *\n");
    	printf("\t\t*******************************\n");
    	printf("\t\t请选择:");
    	scanf("%d",&chioce);
        switch(chioce)
    	{  
    	    case 1:
                MD5();
        		break;
        	default:
	        	break;
    	}
	}while(chioce!=0);
	return 0; 
}  


本文为原创作品,转载请注明出处:http://write.blog.csdn.net/postedit/51736426


附MD5加密网站:http://tool.chinaz.com/tools/md5.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值