MD5
MD5介绍
MD5在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2、MD3和MD4发展而来。
MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个。
MD5的典型应用是对一段信息串 (Message)产生所谓的指纹 (fingerprint),以防止被“篡改”。比方说,你将一段话写在一个文本文件中,并对这个文本文件产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
MD5的链接变量及基本操作
MD5有四个32位的被称作链接变量的整数参数,这是个参数我们定义为A、B、C、D其取值为:
1 2 3 4 | A = 0x67452301; B = 0xefcdab89; C = 0x98badcfe; D = 0x10325476; |
四个非线性操作函数(&是与,|是或,~是非,^是异或):
1 2 3 4 | 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)) |
函数设计
利用上面的四种操作,生成四个重要的计算函数。首先我们声明四个中间变量a,b,c,d,赋值:a = A, b = B, c = C, d = D。然后定义这四个计算函数为:
1 2 3 4 5 6 7 8 9 10 11 | a = b + ((a + F(b, c, d) + Mj + ti) <<< s) FF(a, b, c, d, M[j], s, ti) a = b + ((a + G(b, c, d) + Mj + ti) <<< s) GG(a, b, c, d, M[j], s, ti) a = b + ((a + H(b, c, d) + Mj + ti) <<< s) HH(a, b, c, d, M[j], s, ti) a = b + ((a + I(b, c, d) + Mj + ti) <<< s) II(a, b, c, d, M[j], s, ti) |
其中M[j]表示消息的第j个子分组(从0到15),<<表示循环左移s,常数ti是4294967296*abs(sin(i))的整数部分,i取值从1到64,单位是弧度。
循环计算
定义好上述的四个计算函数后,就可以实现MD5的真正循环计算了。这个循环的循环次数为512位分组的个数。每次循环执行64不计算,上述4个函数每个16次,具体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | //第一轮循环计算M[] 用于每次运算装每组512 bit数据 FF(a,b,c,d,M[0],7,0xd76aa478); FF(d,a,b,c,M[1],12,0xe8c7b756); FF(c,d,a,b,M[2],17,0x242070db); FF(b,c,d,a,M[3],22,0xc1bdceee); FF(a,b,c,d,M[4],7,0xf57c0faf); FF(d,a,b,c,M[5],12,0x4787c62a); FF(c,d,a,b,M[6],17,0xa8304613); FF(b,c,d,a,M[7],22,0xfd469501) ; FF(a,b,c,d,M[8],7,0x698098d8) ; FF(d,a,b,c,M[9],12,0x8b44f7af) ; FF(c,d,a,b,M[10],17,0xffff5bb1) ; FF(b,c,d,a,M[11],22,0x895cd7be) ; FF(a,b,c,d,M[12],7,0x6b901122) ; FF(d,a,b,c,M[13],12,0xfd987193) ; FF(c,d,a,b,M[14],17,0xa679438e) ; FF(b,c,d,a,M[15],22,0x49b40821); //第二轮循环计算 GG(a,b,c,d,M[1],5,0xf61e2562); GG(d,a,b,c,M[6],9,0xc040b340); GG(c,d,a,b,M[11],14,0x265e5a51); GG(b,c,d,a,M[0],20,0xe9b6c7aa) ; GG(a,b,c,d,M[5],5,0xd62f105d) ; GG(d,a,b,c,M[10],9,0x02441453) ; GG(c,d,a,b,M[15],14,0xd8a1e681); GG(b,c,d,a,M[4],20,0xe7d3fbc8) ; GG(a,b,c,d,M[9],5,0x21e1cde6) ; GG(d,a,b,c,M[14],9,0xc33707d6) ; GG(c,d,a,b,M[3],14,0xf4d50d87) ; GG(b,c,d,a,M[8],20,0x455a14ed); GG(a,b,c,d,M[13],5,0xa9e3e905); GG(d,a,b,c,M[2],9,0xfcefa3f8) ; GG(c,d,a,b,M[7],14,0x676f02d9) ; GG(b,c,d,a,M[12],20,0x8d2a4c8a); //第三轮循环计算 HH(a,b,c,d,M[5],4,0xfffa3942); HH(d,a,b,c,M[8],11,0x8771f681); HH(c,d,a,b,M[11],16,0x6d9d6122); HH(b,c,d,a,M[14],23,0xfde5380c) ; HH(a,b,c,d,M[1],4,0xa4beea44) ; HH(d,a,b,c,M[4],11,0x4bdecfa9) ; HH(c,d,a,b,M[7],16,0xf6bb4b60) ; HH(b,c,d,a,M[10],23,0xbebfbc70); HH(a,b,c,d,M[13],4,0x289b7ec6); HH(d,a,b,c,M[0],11,0xeaa127fa); HH(c,d,a,b,M[3],16,0xd4ef3085); HH(b,c,d,a,M[6],23,0x04881d05); HH(a,b,c,d,M[9],4,0xd9d4d039); HH(d,a,b,c,M[12],11,0xe6db99e5); HH(c,d,a,b,M[15],16,0x1fa27cf8) ; HH(b,c,d,a,M[2],23,0xc4ac5665); //第四轮循环计算 II(a,b,c,d,M[0],6,0xf4292244) ; II(d,a,b,c,M[7],10,0x432aff97) ; II(c,d,a,b,M[14],15,0xab9423a7); II(b,c,d,a,M[5],21,0xfc93a039) ; II(a,b,c,d,M[12],6,0x655b59c3) ; II(d,a,b,c,M[3],10,0x8f0ccc92) ; II(c,d,a,b,M[10],15,0xffeff47d); II(b,c,d,a,M[1],21,0x85845dd1) ; II(a,b,c,d,M[8],6,0x6fa87e4f) ; II(d,a,b,c,M[15],10,0xfe2ce6e0); II(c,d,a,b,M[6],15,0xa3014314) ; II(b,c,d,a,M[13],21,0x4e0811a1); II(a,b,c,d,M[4],6,0xf7537e82) ; II(d,a,b,c,M[11],10,0xbd3af235); II(c,d,a,b,M[2],15,0x2ad7d2bb); II(b,c,d,a,M[9],21,0xeb86d391); |
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | #include <Windows.h> #include <stdint.h> #include <stdio.h> //举例用的待处理文件原始数据 uint8_t FileBuff[] = "moxi" ; //"flagby.cn_moxi"; //四个32位链接变量的初始化值 uint32_t A = 0x67452301; uint32_t B = 0xefcdab89; uint32_t C = 0x98badcfe; uint32_t D = 0x10325476; uint32_t a,b,c,d = 0; //4轮逻辑计算中链接变量的过程量 uint32_t FileLen_Byte; //文件填充前的长度(单位 - 字节) uint32_t FileLen_Bit[2]; //文件填充前的长度(单位 - 位 bit) uint8_t MD5_ChangeBuff[64]; //临时缓存区 - 用于补位操作 uint32_t MD5_Buff[16]; //临时缓存区 - 用于每次运算装每组512 bit数据 uint8_t MD5_Data[16]; //最终计算结果 - 文件的MD5值 #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 RL(x, y) (((x) << (y)) | ((x) >> (32 - (y)))) //x向左循环移y位 #define FF(a, b, c, d, x, s, ac) a = b + (RL((a + F(b,c,d) + x + ac),s)) #define GG(a, b, c, d, x, s, ac) a = b + (RL((a + G(b,c,d) + x + ac),s)) #define HH(a, b, c, d, x, s, ac) a = b + (RL((a + H(b,c,d) + x + ac),s)) #define II(a, b, c, d, x, s, ac) a = b + (RL((a + I(b,c,d) + x + ac),s)) //MD5核心算法,4轮共64次计算 void MD5_Calculate( void ) { a = A, b = B, c = C, d = D; /* Round 1 */ FF (a, b, c, d, MD5_Buff[ 0], 7, 0xd76aa478); /**/ /* 1 */ FF (d, a, b, c, MD5_Buff[ 1], 12, 0xe8c7b756); /**/ /* 2 */ FF (c, d, a, b, MD5_Buff[ 2], 17, 0x242070db); /**/ /* 3 */ FF (b, c, d, a, MD5_Buff[ 3], 22, 0xc1bdceee); /**/ /* 4 */ FF (a, b, c, d, MD5_Buff[ 4], 7, 0xf57c0faf); /**/ /* 5 */ FF (d, a, b, c, MD5_Buff[ 5], 12, 0x4787c62a); /**/ /* 6 */ FF (c, d, a, b, MD5_Buff[ 6], 17, 0xa8304613); /**/ /* 7 */ FF (b, c, d, a, MD5_Buff[ 7], 22, 0xfd469501); /**/ /* 8 */ FF (a, b, c, d, MD5_Buff[ 8], 7, 0x698098d8); /**/ /* 9 */ FF (d, a, b, c, MD5_Buff[ 9], 12, 0x8b44f7af); /**/ /* 10 */ FF (c, d, a, b, MD5_Buff[10], 17, 0xffff5bb1); /**/ /* 11 */ FF (b, c, d, a, MD5_Buff[11], 22, 0x895cd7be); /**/ /* 12 */ FF (a, b, c, d, MD5_Buff[12], 7, 0x6b901122); /**/ /* 13 */ FF (d, a, b, c, MD5_Buff[13], 12, 0xfd987193); /**/ /* 14 */ FF (c, d, a, b, MD5_Buff[14], 17, 0xa679438e); /**/ /* 15 */ FF (b, c, d, a, MD5_Buff[15], 22, 0x49b40821); /**/ /* 16 */ /* Round 2 */ GG (a, b, c, d, MD5_Buff[ 1], 5, 0xf61e2562); /**/ /* 17 */ GG (d, a, b, c, MD5_Buff[ 6], 9, 0xc040b340); /**/ /* 18 */ GG (c, d, a, b, MD5_Buff[11], 14, 0x265e5a51); /**/ /* 19 */ GG (b, c, d, a, MD5_Buff[ 0], 20, 0xe9b6c7aa); /**/ /* 20 */ GG (a, b, c, d, MD5_Buff[ 5], 5, 0xd62f105d); /**/ /* 21 */ GG (d, a, b, c, MD5_Buff[10], 9, 0x02441453); /**/ /* 22 */ GG (c, d, a, b, MD5_Buff[15], 14, 0xd8a1e681); /**/ /* 23 */ GG (b, c, d, a, MD5_Buff[ 4], 20, 0xe7d3fbc8); /**/ /* 24 */ GG (a, b, c, d, MD5_Buff[ 9], 5, 0x21e1cde6); /**/ /* 25 */ GG (d, a, b, c, MD5_Buff[14], 9, 0xc33707d6); /**/ /* 26 */ GG (c, d, a, b, MD5_Buff[ 3], 14, 0xf4d50d87); /**/ /* 27 */ GG (b, c, d, a, MD5_Buff[ 8], 20, 0x455a14ed); /**/ /* 28 */ GG (a, b, c, d, MD5_Buff[13], 5, 0xa9e3e905); /**/ /* 29 */ GG (d, a, b, c, MD5_Buff[ 2], 9, 0xfcefa3f8); /**/ /* 30 */ GG (c, d, a, b, MD5_Buff[ 7], 14, 0x676f02d9); /**/ /* 31 */ GG (b, c, d, a, MD5_Buff[12], 20, 0x8d2a4c8a); /**/ /* 32 */ /* Round 3 */ HH (a, b, c, d, MD5_Buff[ 5], 4, 0xfffa3942); /**/ /* 33 */ HH (d, a, b, c, MD5_Buff[ 8], 11, 0x8771f681); /**/ /* 34 */ HH (c, d, a, b, MD5_Buff[11], 16, 0x6d9d6122); /**/ /* 35 */ HH (b, c, d, a, MD5_Buff[14], 23, 0xfde5380c); /**/ /* 36 */ HH (a, b, c, d, MD5_Buff[ 1], 4, 0xa4beea44); /**/ /* 37 */ HH (d, a, b, c, MD5_Buff[ 4], 11, 0x4bdecfa9); /**/ /* 38 */ HH (c, d, a, b, MD5_Buff[ 7], 16, 0xf6bb4b60); /**/ /* 39 */ HH (b, c, d, a, MD5_Buff[10], 23, 0xbebfbc70); /**/ /* 40 */ HH (a, b, c, d, MD5_Buff[13], 4, 0x289b7ec6); /**/ /* 41 */ HH (d, a, b, c, MD5_Buff[ 0], 11, 0xeaa127fa); /**/ /* 42 */ HH (c, d, a, b, MD5_Buff[ 3], 16, 0xd4ef3085); /**/ /* 43 */ HH (b, c, d, a, MD5_Buff[ 6], 23, 0x04881d05); /**/ /* 44 */ HH (a, b, c, d, MD5_Buff[ 9], 4, 0xd9d4d039); /**/ /* 45 */ HH (d, a, b, c, MD5_Buff[12], 11, 0xe6db99e5); /**/ /* 46 */ HH (c, d, a, b, MD5_Buff[15], 16, 0x1fa27cf8); /**/ /* 47 */ HH (b, c, d, a, MD5_Buff[ 2], 23, 0xc4ac5665); /**/ /* 48 */ /* Round 4 */ II (a, b, c, d, MD5_Buff[ 0], 6, 0xf4292244); /**/ /* 49 */ II (d, a, b, c, MD5_Buff[ 7], 10, 0x432aff97); /**/ /* 50 */ II (c, d, a, b, MD5_Buff[14], 15, 0xab9423a7); /**/ /* 51 */ II (b, c, d, a, MD5_Buff[ 5], 21, 0xfc93a039); /**/ /* 52 */ II (a, b, c, d, MD5_Buff[12], 6, 0x655b59c3); /**/ /* 53 */ II (d, a, b, c, MD5_Buff[ 3], 10, 0x8f0ccc92); /**/ /* 54 */ II (c, d, a, b, MD5_Buff[10], 15, 0xffeff47d); /**/ /* 55 */ II (b, c, d, a, MD5_Buff[ 1], 21, 0x85845dd1); /**/ /* 56 */ II (a, b, c, d, MD5_Buff[ 8], 6, 0x6fa87e4f); /**/ /* 57 */ II (d, a, b, c, MD5_Buff[15], 10, 0xfe2ce6e0); /**/ /* 58 */ II (c, d, a, b, MD5_Buff[ 6], 15, 0xa3014314); /**/ /* 59 */ II (b, c, d, a, MD5_Buff[13], 21, 0x4e0811a1); /**/ /* 60 */ II (a, b, c, d, MD5_Buff[ 4], 6, 0xf7537e82); /**/ /* 61 */ II (d, a, b, c, MD5_Buff[11], 10, 0xbd3af235); /**/ /* 62 */ II (c, d, a, b, MD5_Buff[ 2], 15, 0x2ad7d2bb); /**/ /* 63 */ II (b, c, d, a, MD5_Buff[ 9], 21, 0xeb86d391); /**/ /* 64 */ A += a; B += b; C += c; D += d; } int main( void ) { uint8_t i = 0; //获取加密数据长度(单位 - 字节) FileLen_Byte = ( sizeof (FileBuff) / sizeof (FileBuff[0])) - 1; //这里要注意减去字符串结束符'\0'占的一个字节长度 //分组循环运算直至文件结束(每组 512 bit 即 每组 64 字节) for (i = 0; i < FileLen_Byte / 64; i++) { memset (MD5_Buff, 0, 64); //初始化 MD5_Buff 数组为0 memcpy (&MD5_Buff[0], &FileBuff[i * 64], 64); //高低位倒序赋值(大小端转换) MD5_Calculate(); //进行四轮逻辑计算 } //最后一组不足512 bit,补位 “1” 和 “0” memset (MD5_Buff, 0, 64); //初始化 MD5_Buff(数组大小16,数据类型长度4字节) memset (MD5_ChangeBuff, 0, 64); //初始化 MD5_ChangeBuff(数组大小64,数据类型长度1字节) memcpy (MD5_ChangeBuff, &FileBuff[FileLen_Byte - (FileLen_Byte % 64)], FileLen_Byte % 64); MD5_ChangeBuff[FileLen_Byte % 64] = 128; //在文件末尾先补一个1和七个0,十进制128的二进制即1000 0000 memcpy (&MD5_Buff[0], &MD5_ChangeBuff[0], 64); //高低位倒序赋值(大小端转换) //补完第一个字节,128的二进制即1000 0000后,判断这一组还有没有空位放 文件填充前的长度(64bit,即8个字节) //若不够位置放,则再补一组512 bit,在那组的最后放文件填充前长度。 if ((FileLen_Byte % 64) > 55) //64 - 1 - 8 = 55 { MD5_Calculate(); //进行四轮逻辑计算 memset (MD5_Buff, 0, 64); //初始化 MD5_Buff 数组为0 } //在最后一个分组的最后补上原始文件填充前的长度(单位 - 位 bit) FileLen_Bit[1] = FileLen_Byte / 0x20000000; FileLen_Bit[0] = (FileLen_Byte % 0x20000000) * 8; //这一步要注意大小端转换,和前面的转换方式不太一样 memcpy (&MD5_Buff[14], FileLen_Bit, 8); //末尾加入原文件的bit长度(文件填充前的长度(单位 - bit)) MD5_Calculate(); memcpy (&MD5_Data[0], &A, 4); //高低位倒序赋值 memcpy (&MD5_Data[4], &B, 4); //高低位倒序赋值 memcpy (&MD5_Data[8], &C, 4); //高低位倒序赋值 memcpy (&MD5_Data[12], &D, 4); //高低位倒序赋值 // 打印出MD5值 - 想打印的时候就删掉注释 printf ( "\r\n MD5值为: " ); for (i = 0; i < 16; i++) { printf ( " %02x" , MD5_Data[i]); } getchar (); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!