解析MD5加密算法(C语言)

目录

前提概要:

MD5加密4步骤:

C语言实现MD5算法:(假设加密 iscbupt )

附上运行中间结果图:

字符串和文件加密实例:


前提概要:

本篇内容基于haroroda博客的MD5加密算法(c语言实现)和 艾蔓草博客的C语言实现md5函数代码,只是进行简单的融合并附上自己的理解而已,有需要的可以自己浏览上面两篇优秀的博客。

MD5加密4步骤:

    (1)附加填充位 

      课本原话:填充一个 ‘1’ 和若干个 ‘0’ 使其长度模 512 与 448 同余,然后再将消息的真实长度以 64bit 表示附加在填充结果后面,从而使得消息长度恰好为 512bit 的整数倍。

      举例说明:

      如明文为 iscbupt (7字符,56bits)

      其 16 进制 ascII 码是105,115,99,98,117,112,116,转换成二进制便是 01101001 01110011 01100011 01100010 01110101 01110000 01110100,这是长度为 56 ,要使其长度模 512 与 448 同余,则需补充一个 ‘1’ 和 391 个 ‘0’ 。因为消息长度为 56,所以用 64 位二进制表示为 00~00(56个零)00111000。到目前为止 512 位全部填充完整了~

    (2)初始化链接变量 

      课本原话:MD5 中有 A、B、C、D 4 个 32 位寄存器,最开始存放 4 个固定的 32 位的整数参数,即初始链接变量,这些参数用于第 1 轮运算。(第 1 轮之后值就会变化)

      A=0x12345678,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210

   (3)分组处理(迭代压缩)  

     课本原话:MD5 算法的分组处理(压缩函数)与分组密码的分组处理相似。它由4大轮组成,512bit 的消息分组 M[i] 被分成 16 个子分组(每个子分组为 32bit )参与每大轮中16步函数运算,即每大轮包括 16 个小步骤。

每步的输入是 4 个 32bit 的链接变量(也就是A、B、C、D)和一个32bit的消息分组(就是 M[i] ),输出为 32 位值。经过 4 轮共 64 步后,得到的 4 个寄存器值分别与输入链接变量(也就是初始的A、B、C、D)进行模加,即是当前消息的中间散列值。

     明文是 iscbupt 的 M[i] 如下:

     M[0]:01101001 01110011 01100011 01100010

     M[1]:01110101 01110000 01110100 10000000



     M[2]:00000000 00000000 00000000 00000000



     ................



     M[14]:00111000 00000000 00000000 00000000 #这里是我们前面补充的最后64bits长度



     M[15]:00000000 00000000 00000000 00000000

   (4)分组处理中步函数

     所有大轮(上文所说的 4 大轮)里的所有小轮(16轮)都是同一个步函数 A = B + (( A + f(B,C,D) + M[j] + T[i]) <<< s )) 操作即 B、C、D进入 f 函数(这里的 f 函数就是课本里的非线性函数:包含F、G、H、I 这四种函数),得到的结果与 A 模加,再与 M[j] 模加(这里的 j 与第几大轮第几小轮有关),然后继续与 T[i] 模加(这里的 i 从 1 取到 64 ),然后进行循环左移 s 位(左移的 2 位数也与第几大轮第几小轮有关),结果再与 B 模加,最后得到的结果终值赋值给 A 。

    一小轮结束后将 A 赋值给 B,B 赋值给 C,C 赋值给 D,原本的 D 赋值给 A,赋值完的 A、B、C、D 便可以进入下一轮。

    下面来说下上文 j、左移步数 step、T[i] 的取值情况:

     第一大轮:

      j 在这大轮是按顺序从 0 取到 15

     第 1、5、9、13 小轮 step=7;第 2、6、10、14 小轮 step=12;第 3、7、11、15 小轮 step=17;第 4、8、12、16 小轮 step=22

      第二大轮:

      j 的取值顺序为 ----- 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 

     第 1、5、9、13 小轮 step=5;第 2、6、10、14 小轮 step=9;第 3、7、11、15 小轮 step=14;第 4、8、12、16小轮 step=20

     第三大轮:

     j 的取值顺序为----- 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 

     第 1、5、9、13 小轮 step=4;第 2、6、10、14 小轮 step=11;第 3、7、11、15 小轮 step=16;第 4、8、12、16 小轮 step=23

     第四大轮:

      j 的取值顺序为-----0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9

      第 1、5、9、13 小轮 step=6;第 2、6、10、14 小轮 step=10;第 3、7、11、15 小轮 step=15;第 4、8、12、16 小轮 step=21

T[i]= 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf,

0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af,

0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e,

0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,

0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6,

0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,

0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,

0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,

0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039,

0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97,

0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d,

0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,

0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391

MD5加密中注意点:

1. MD5 加密算法里面的所有模加都是模 2 的 32 次加,而不是模 2 加。

举例说明下模 2 的 32 次加:(就是简单的二进制加法取前 32 位而已)

11101000......(省略了24个‘0’)+01110000.........(省略了24个‘0’)=101011000.......(省略了24个‘0’),共33位,取后32位最终得到01011000........(省略了24个‘0’)。

2.初始的A、B、C、D 4个链接变量与 M[j] 在进入步函数前要先经过大小端处理,T[i]不需要。

3.位数填充时(64 bit),若长度的二进制位数不足,需要在二进制前补齐至 8 的整数倍而不是 4 的整数倍。如400=110010000(补齐 8 的整数倍,共 16 位)

补齐后是00000001 10010000而不是00011001 00000000

4.大小端处理不是单纯指 12345678 -> 78563412,之所以有前面这种变换,是因为 12、34、56、78 分别表示 4 个十进制数,也就是说表示第 1 个十进制数的十六进制数经过转换放在最后,第 2 个放在第 1 个前。当 1234 表示第 1 个十进制数、5678 表示第 2 个十进制数时,12345678 -> 56781234 而不是 78563412。如:明文长度为 400, M[14] 为 0x01900000,转换后为 0x00000190 而不是 0x00009001

C语言实现MD5算法:(假设加密 iscbupt )

源文件如下:md5.h

#ifndef MD5_H

#define MD5_H



/*

只引用一次头文件:(头文件名转为大写并用 '_' 代替 '.' ,举例:md5.h写为MD5_H )

#ifndef HEADER_FILE

#define HEADER_FILE

the entire header file context

#endif

*/



typedef struct #定义 md5 加密算法的结构

{

unsigned int count[2]; #md5 加密算法的第一步附加填充位,这里 32 位 Int 要看成 256bits ,count[2] 就是512bits

unsigned int state[4]; #md5 加密算法的第二步初始化链接变量,这里存放 A、B、C、D 4 个 32 位寄存器,

unsigned char buffer[64]; #md5 加密算法的第三步分组处理(迭代压缩),这里存放 A、B、C、D 4 个 32 位寄存器,

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



/*

md5 加密算法的第四步:

分组处理中步函数课本里的非线性函数,

包含F、G、H、I这四种函数。

*/



#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) #定义分组处理的步函数中的移位 step。



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

}



/*

这里定义 4 大轮里的所有小轮(16 轮)的同一个步函数:

A = B + (( A + f(B,C,D) + M[j] + T[i]) <<< s ))

上面的 '\' 是续行符

*/



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.c:

#include 

#include "md5.h"



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}; #这里有 64 个char类型,要按 bit 来看,所以是 64*8=512bits ,我们第一步的时候说填充一个 ‘1’ 和若干个 ‘0’ 使其长度模 512 与 448 同余,所以这里第一个 0x80 就是我们填充的第一个 1 造成的。放 512bits 在这里是用于后面补位的时候截取,比如我们加密 iscbupt (7字符,56bits),那么就要补充 312bits 在这里截取前 39 位。





/********************************************************

* 名 称: MD5Init()

* 功 能: 初始化MD5结构体

* 入口参数:

context:要初始化的MD5结构体

* 出口参数: 无

*********************************************************/



void MD5Init(MD5_CTX *context)

{

context->count[0] = 0; #初始化中这里存放的是传入参数的 bits 位数

context->count[1] = 0;

context->state[0] = 0x67452301; #初始化中这里是 A、B、C、D 4 个 32 位寄存器的初始值

context->state[1] = 0xEFCDAB89;

context->state[2] = 0x98BADCFE;

context->state[3] = 0x10325476;

}





/*********************************************************

* 名 称: MD5Update()

* 功 能: 将要加密的信息传递给初始化过的MD5结构体,无返回值

* 入口参数:

context:初始化过了的MD5结构体

input:需要加密的信息,可以任意长度

inputLen:指定input的长度

* 出口参数: 无

*********************************************************/



void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen) #先以传入参数 iscbupt (7字符,56bits)为准来讨论

{

unsigned int i = 0,index = 0,partlen = 0;

index = (context->count[0] >> 3) & 0x3F;



#第一次调用:index = 0 ,这里右移 3 位得看成除以 8,是计算要加密的字符数的(char),第一次调用 MD5Update 中并没有派上用场,在后面的 MD5Final 函数中会有第 2、3 次调用 MD5Update ,那时候才会用上。& 0x3F是要保证截取的是非 512bits 的余数部分,因为 2 的 6 次方是 64 位 512bits

#第二次调用:index = 7

#第三次调用:index = 56



partlen = 64 - index;



#第一次调用:partlen = 64,这里 partlen 是计算在不断补位中 context->count 所占的 bits 数距离 512 的整数倍还差多少位( char 型)。

#第二次调用:partlen = 57

#第三次调用:partlen = 8



context->count[0] += inputlen << 3;



#第一次调用:context->count[0] = 56,这里左移 3 位要看成乘 8,这里是计算输入的字符的 bits 数,用于给后面加密第一步附加填充位来参考

#第二次调用:inputlen 是 MD5Final 中的 padlen = 49,所以 context->count[0] = 448,已经模 512 与 448 同余了。

#第三次调用:inputlen 是 MD5Final 中的 8,所以 context->count[0] = 512,已经是最终的长度了。



if(context->count[0] < (inputlen << 3))

context->count[1]++;



#这里不明觉厉



context->count[1] += inputlen >> 29;





#第一次调用:由于我们传入的 iscbupt (7字符,56bits)不足 64 位的 512bits 所以不进入该循环。

#第二次调用:由于我们传入的 MD5Final 中的 padlen = 49 不足新 partlen = 57 ,所以不进入该循环。

#第二次调用:由于我们传入的 MD5Final 中的 8 足够新 partlen = 8 ,所以进入该循环,开始加密。



if(inputlen >= partlen)



#如果传入的参数的长度直接就满足 64 位的 512bits 就先把这部分加密,因为每次每次只能加密 512bits ,后面补位上去的 64bits 长度什么的等补齐到 512bits 的整数倍后再继续加密。

{

memcpy(&context->buffer[index],input,partlen); #把 64 位的 512bits 复制到 context->buffer[index] 中进行第一个 512bits 的加密。

MD5Transform(context->state,context->buffer); #md5加密算法

for(i = partlen;i+64 <= inputlen;i+=64) #把符合 512bits 的部分继续加密,这里非 512bits 部分的余数并没有进入加密中,因为要在后面补齐 512bits 后才能用来加密。

MD5Transform(context->state,&input[i]);

index = 0;

}

else

{

i = 0;

}

memcpy(&context->buffer[index],&input[i],inputlen-i); #这里把非 512bits 部分的余数存入context->buffer[index] 中,用于在 MD5Final 中补位。

}



/*********************************************************

* 名 称: MD5Final()

* 功 能: 转换成32位的16进制字符串。

context:初始化过了的MD5结构体

digest[16]:用于承接加密后的 32 位密文

* 出口参数: 无

*********************************************************/



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

{

unsigned int index = 0,padlen = 0;

unsigned char bits[8]; #这里 8 位 char 共 64bits 是加密第一步中附加填充位时把真实长度以 64bit 表示附加在填充结果后面,以达到 512bits整数倍的长度。



index = (context->count[0] >> 3) & 0x3F; #在第一次调用 MD5Update 中 context->count[0] 被赋值了传入参数的 bits 数,这里右移 3 位就是除 8,就是被赋值会传入参数的 char 长度,7位。& 0x3F是要保证截取的是非 512bits 的余数部分,因为 2 的 6 次方是 64 位 512bits



padlen = (index < 56)?(56-index):(120-index);

#这里 padlen = 49 ,这是判断传入参数是否小于 56,因为最后的 8 位 64bits 是用来补充真实长度的,如果传入参数大于 56 位,那总长度就以 1024bits 来算。



MD5Encode(bits,context->count,8); #第一次调用 MD5Update 中 context->count[0] 值为 56bits ,总共64 位的 context->count 拆分成 8 个 8 位存放到 bits 中,由于这里存放的是 char 类型,所以 56 以 ASCII 码值 8 的形式存入。



MD5Update(context,PADDING,padlen); #第二次调用 MD5Update 截取 PADDING 的前 padlen 位来做补位,使其使其长度模 512 与 448 同余

MD5Update(context,bits,8); #第三次调用 MD5Update 截取 bits 的前 8 位来做最后的真实长度以 64bit 表示附加在填充结果后面,从而使得消息长度恰好为 512bit 的整数倍的补位。

MD5Encode(digest,context->state,16);

}



/*********************************************************

* 名 称: MD5Encode()

* 功 能: 将 32 位的 int 类型拆分成 8 位的 char 类型,存放到 4 个数组中,要注意的是存放的值是 ASCII 码的形式。

* 入口参数:

input:要拆分的 int 类型的字符串

len :字符串的长度

output:作为拆分后的承接载体

* 出口参数: 无

*********************************************************/



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;

}

}



/*********************************************************

* 名 称: MD5Decode()

* 功 能: 将 8 位的 char 类型拼凑成成 32 位的 int 类型,存放到 1 个数组中,要注意的是存放的值是数字型。

* 入口参数:

input:要拼凑的 char 类型的字符串

len :字符串的长度

output:作为拼凑后的承接载体

* 出口参数: 无

*********************************************************/



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;

}

}



/*********************************************************

* 名 称: MD5Transform()

* 功 能: md5 加密算法实现

* 入口参数:

state[4]:A、B、C、D 4 个 32 位寄存器

block[64] :完整的符合要求的 512bits 整数倍的加密参数

* 出口参数: 无

*********************************************************/



void MD5Transform(unsigned int state[4],unsigned char block[64])

{

unsigned int a = state[0]; #这里是 A、B、C、D 4 个 32 位寄存器的初始值,用于第1轮运算。

unsigned int b = state[1];

unsigned int c = state[2];

unsigned int d = state[3];



unsigned int x[64];

MD5Decode(x,block,64); #512bits 的消息分组M[i] 被分成 16 个子分组(每个子分组为 32bits)参与 4 大轮中没轮 16 步函数运算。



/*

 所有大轮里的所有小轮都是同一个步函数 A = B + (( A + f(B,C,D) + M[j] + T[i]) <<< s ))操作 ,

一小轮结束后将 A 赋值给 B,B 赋值给 C,C 赋值给 D,原本的 D 赋值给 A,

赋值完的 A、B、C、D 便可以进入下一轮。

*/

/* Round 1 */

FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */

FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */

FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */

FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */

FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */

FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */

FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */

FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */

FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */

FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */

FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */

FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */

FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */

FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */

FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */

FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */



/* Round 2 */

GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */

GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */

GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */

GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */

GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */

GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */

GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */

GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */

GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */

GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */

GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */

GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */

GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */

GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */

GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */

GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */



/* Round 3 */

HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */

HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */

HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */

HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */

HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */

HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */

HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */

HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */

HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */

HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */

HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */

HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */

HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */

HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */

HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */

HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */



/* Round 4 */

II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */

II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */

II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */

II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */

II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */

II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */

II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */

II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */

II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */

II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */

II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */

II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */

II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */

II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */

II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */

II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */



/*

经过 4 轮共 64 步后,得到的 4 个寄存器值分别与输入链接变量(也就是初始的A、B、C、D)进行模加,

即是当前消息的中间散列值,这里是 16 位的,要转成 32 位 16 进制的密文。

*/

state[0] += a;

state[1] += b;

state[2] += c;

state[3] += d;

}

附上运行中间结果图:

解析MD5加密算法(C语言)_第1张图片

字符串和文件加密实例:

对字符串进行加密:

#include 

#include 

#include "md5.h"

#include 

#include 

#include 

#include 



void main( void )

{

int read_len;

int i ;

char temp[8]={0};

unsigned char digest[16]; //存放结果

char hexbuf[128]="12334567";

unsigned char decrypt[16]={0};

unsigned char decrypt32[64]={0};



MD5_CTX md5c;



MD5Init(&md5c); //初始化

read_len = strlen(hexbuf);

MD5Update(&md5c,(unsigned char *)hexbuf,read_len);



MD5Final(&md5c,decrypt);

strcpy((char *)decrypt32,"");



for(i=0;i<16;i++)

{

sprintf(temp,"%02x",decrypt[i]);

strcat((char *)decrypt32,temp);

}

printf("md5:%s\n",decrypt32);



return;

}

实例2 文件加密:

#include 

#include 

#include "md5.h"

#include 

#include 

#include 

#include 



#define FORWORD_FW "123.c"



int calc_md5(char*filename,char*dest)

{

int i;

int filelen = 0;

int read_len;

char temp[8]={0};

char hexbuf[128]={0};

unsigned char decrypt[16]={0};

unsigned char decrypt32[64]={0};

MD5_CTX md5;

char fw_path[128];



int fdf;



fdf = open(filename,O_RDWR);

if(fdf<0)

{

printf("%s not exist\n",FORWORD_FW);

return -1;

}



MD5Init(&md5);

while(1)

{

read_len = read(fdf, hexbuf,sizeof(hexbuf));

if (read_len <0) {

close(fdf);

return -1;

}

if(read_len==0)

{

break;

}

filelen += read_len;

MD5Update(&md5,(unsigned char *)hexbuf,read_len);

}





MD5Final(&md5,decrypt);

strcpy((char *)decrypt32,"");



for(i=0;i<16;i++)

{

sprintf(temp,"%02x",decrypt[i]);

strcat((char *)decrypt32,temp);

}

strcpy(dest,decrypt32);



printf("md5:%s len=%d\n",dest,filelen);

close(fdf);



return filelen;

}

int main(int argc, char *argv[])

{

int ret;

int filelen;

char md5_str[64]={0};

char cmd[256]={0};



filelen = calc_md5(FORWORD_FW,md5_str);

if(filelen<0)

{

printf("calc_md5 fail\n");

return -1;

}



return 0;

}

你可能感兴趣的:(笔记,ctf)