需要特别注意两点:
一是算法涉及3套序列分量:
1,参与首个分组的初始序列分量,由算法规范指定固定值.代码中记A,B,C,D
2,在各分组之间传递的序列分量,也称链接变量.最终结果由本套变量拼接,代码中记为linka,linkb,linkc,linkd;
3,在每个分组计算过程中用到的临时序列分量,仅参与分组内计算,不在分组之间传递,代码中记为a,b,c,d.
二是每个分组计算结束时,是将本分组临时的序列分量abcd加上参与本分组计算的链接变量(linka,linkb,linkc,linkd)的结果作为下一分组的链接变量传递下去,而不是将本分组临时序列分量abcd加上A,B,C,D.
由于MD5算法中涉及的常量多为2的倍数,所以代码中有关乘法和除法都通过移位来实现.
#include<iostream> using namespace std; //将x循环左移n位 #define CYC_SHL_32(x, n) (((x) << (n)) | ((x) >> (32-(n)))) //非线性函数,每组四轮,每轮使用依次一个 #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 FF(a ,b ,c ,d ,Mj ,s ,ti ) (a) = (b) + ( CYC_SHL_32(((a) + F((b),(c),(d)) + (Mj) + (ti)), (s))) #define GG(a ,b ,c ,d ,Mj ,s ,ti ) (a) = (b) + ( CYC_SHL_32(((a) + G((b),(c),(d)) + (Mj) + (ti)), (s))) #define HH(a ,b ,c ,d ,Mj ,s ,ti ) (a) = (b) + ( CYC_SHL_32(((a) + H((b),(c),(d)) + (Mj) + (ti)), (s))) #define II(a ,b ,c ,d ,Mj ,s ,ti ) (a) = (b) + ( CYC_SHL_32(((a) + I((b),(c),(d)) + (Mj) + (ti)), (s))) //第1/4轮的循环左移次数,循环使用 #define FS1 7 #define FS2 12 #define FS3 17 #define FS4 22 //第2/4轮的循环左移次数,循环使用 #define GS1 5 #define GS2 9 #define GS3 14 #define GS4 20 //第3/4轮的循环左移次数,循环使用 #define HS1 4 #define HS2 11 #define HS3 16 #define HS4 23 //第4/4轮的循环左移次数,循环使用 #define IS1 6 #define IS2 10 #define IS3 15 #define IS4 21 //初始序列 #define A 0x67452301 #define B 0xefcdab89 #define C 0x98badcfe #define D 0x10325476 //链接变量 unsigned int linka; unsigned int linkb; unsigned int linkc; unsigned int linkd; //四位二进制序列转换为一个十六进制字符 const char str16[] = "0123456789abcdef"; void one_group(unsigned int M[]) { //临时链接变量 unsigned int a = linka, b = linkb, c = linkc, d = linkd; //第1/4轮,含有16步 FF(a, b, c, d, M[ 0], FS1, 0xd76aa478); FF(d, a, b, c, M[ 1], FS2, 0xe8c7b756); FF(c, d, a, b, M[ 2], FS3, 0x242070db); FF(b, c, d, a, M[ 3], FS4, 0xc1bdceee); FF(a, b, c, d, M[ 4], FS1, 0xf57c0faf); FF(d, a, b, c, M[ 5], FS2, 0x4787c62a); FF(c, d, a, b, M[ 6], FS3, 0xa8304613); FF(b, c, d, a, M[ 7], FS4, 0xfd469501); FF(a, b, c, d, M[ 8], FS1, 0x698098d8); FF(d, a, b, c, M[ 9], FS2, 0x8b44f7af); FF(c, d, a, b, M[10], FS3, 0xffff5bb1); FF(b, c, d, a, M[11], FS4, 0x895cd7be); FF(a, b, c, d, M[12], FS1, 0x6b901122); FF(d, a, b, c, M[13], FS2, 0xfd987193); FF(c, d, a, b, M[14], FS3, 0xa679438e); FF(b, c, d, a, M[15], FS4, 0x49b40821); //第2/4轮,含有16步 GG(a, b, c, d, M[ 1], GS1, 0xf61e2562); GG(d, a, b, c, M[ 6], GS2, 0xc040b340); GG(c, d, a, b, M[11], GS3, 0x265e5a51); GG(b, c, d, a, M[ 0], GS4, 0xe9b6c7aa); GG(a, b, c, d, M[ 5], GS1, 0xd62f105d); GG(d, a, b, c, M[10], GS2, 0x02441453); GG(c, d, a, b, M[15], GS3, 0xd8a1e681); GG(b, c, d, a, M[ 4], GS4, 0xe7d3fbc8); GG(a, b, c, d, M[ 9], GS1, 0x21e1cde6); GG(d, a, b, c, M[14], GS2, 0xc33707d6); GG(c, d, a, b, M[ 3], GS3, 0xf4d50d87); GG(b, c, d, a, M[ 8], GS4, 0x455a14ed); GG(a, b, c, d, M[13], GS1, 0xa9e3e905); GG(d, a, b, c, M[ 2], GS2, 0xfcefa3f8); GG(c, d, a, b, M[ 7], GS3, 0x676f02d9); GG(b, c, d, a, M[12], GS4, 0x8d2a4c8a); //第3/4轮,含有16步 HH(a, b, c, d, M[ 5], HS1, 0xfffa3942); HH(d, a, b, c, M[ 8], HS2, 0x8771f681); HH(c, d, a, b, M[11], HS3, 0x6d9d6122); HH(b, c, d, a, M[14], HS4, 0xfde5380c); HH(a, b, c, d, M[ 1], HS1, 0xa4beea44); HH(d, a, b, c, M[ 4], HS2, 0x4bdecfa9); HH(c, d, a, b, M[ 7], HS3, 0xf6bb4b60); HH(b, c, d, a, M[10], HS4, 0xbebfbc70); HH(a, b, c, d, M[13], HS1, 0x289b7ec6); HH(d, a, b, c, M[ 0], HS2, 0xeaa127fa); HH(c, d, a, b, M[ 3], HS3, 0xd4ef3085); HH(b, c, d, a, M[ 6], HS4, 0x04881d05); HH(a, b, c, d, M[ 9], HS1, 0xd9d4d039); HH(d, a, b, c, M[12], HS2, 0xe6db99e5); HH(c, d, a, b, M[15], HS3, 0x1fa27cf8); HH(b, c, d, a, M[ 2], HS4, 0xc4ac5665); //第4/4轮,含有16步 II(a, b, c, d, M[ 0], IS1, 0xf4292244); II(d, a, b, c, M[ 7], IS2, 0x432aff97); II(c, d, a, b, M[14], IS3, 0xab9423a7); II(b, c, d, a, M[ 5], IS4, 0xfc93a039); II(a, b, c, d, M[12], IS1, 0x655b59c3); II(d, a, b, c, M[ 3], IS2, 0x8f0ccc92); II(c, d, a, b, M[10], IS3, 0xffeff47d); II(b, c, d, a, M[ 1], IS4, 0x85845dd1); II(a, b, c, d, M[ 8], IS1, 0x6fa87e4f); II(d, a, b, c, M[15], IS2, 0xfe2ce6e0); II(c, d, a, b, M[ 6], IS3, 0xa3014314); II(b, c, d, a, M[13], IS4, 0x4e0811a1); II(a, b, c, d, M[ 4], IS1, 0xf7537e82); II(d, a, b, c, M[11], IS2, 0xbd3af235); II(c, d, a, b, M[ 2], IS3, 0x2ad7d2bb); II(b, c, d, a, M[ 9], IS4, 0xeb86d391); linka += a; linkb += b; linkc += c; linkd += d; } //对字符串计算MD5.三个形参,表示信息源为字符串,而非文件路径 void md5(char* pstr, unsigned long long len_B_, char* md5str) { unsigned long long //考虑超长字符串 len_B = len_B_ - 1, //当信息源是字符串时,最后一个字节为'\0',为结束标志,不计数,故需减1 group_num = len_B >> 6; //不含填充信息的分组数量,可取值0.右移6位,相当于除以64的商 int mod64Byte = len_B & 0x3F; //信息的字节数除以64的余数 unsigned int group[16]; //表示一个分组,共32*16=512 bit,步幅为4字节 unsigned char* pchar = (unsigned char*)group; //指向分组的首地址,步幅为1字节. //四个链接变量初值 linka = A; linkb = B; linkc = C; linkd = D; //处理不含填充信息的分组,共有group_num个 for (int i = 0; i < group_num; i++) { //i << 6:表示i乘以64,为一个分组的字节数,也为分组首地址之间的步幅 //为减少从数据源大量复制数据的时间,直接指向数据源需要的分组数据,而不进行复制 one_group((unsigned int*)(pstr + (i << 6))); } //mod64Byte < 56,意味着含有填充信息的分组只有一组 if (mod64Byte < 56) { for (int i = 0; i < 14; i++) group[i] = 0; for (int i = 0; i < mod64Byte; i++) *(pchar + i) = *(pstr + (group_num<<6)+ i); *(pchar + mod64Byte) = 0x80; //扩展,原信息的bit数量,64位. *((unsigned long long*) & group[14]) = len_B << 3; one_group(group); } else//mod64Byte >= 56,意味着含有填充信息的分组有两组 { //初始化倒数第二个分组各bit为0 for (int i = 0; i < 16; i++) group[i] = 0; //倒数第二个分组所需的非填充数据在数据源中的偏移量,单位:字节 group_num <<= 6; //从数据源中截取尾部不足一个分组的数据 for (int i = 0; i < mod64Byte; i++) *(pchar + i) = *(pstr + group_num + i); //该字节的最高位填充1 *(pchar + mod64Byte) = 0x80; //计算倒数第二个分组 one_group(group); //初始化最后一个分组前56个字节各bit为0 for (int i = 0; i < 14; i++) group[i] = 0; //扩展,原信息的bit数量,64位.在内存中小端存放(数据的低字节放在内存的低地址) *((unsigned long long*) & group[14]) = len_B << 3; //计算最后一个分组 one_group(group); } //取得最终MD5的16进制字符串 for (int i = 0; i < 4; i++) { md5str[(i << 1)] = str16[(*((unsigned char*)&linka + i))>>4]; md5str[(i << 1) +1] = str16[(*((unsigned char*)&linka + i)) & 0x0F ]; md5str[(i << 1) +8] = str16[(*((unsigned char*)&linkb + i)) >> 4]; md5str[(i << 1) + 9] = str16[(*((unsigned char*)&linkb + i)) & 0x0F]; md5str[(i << 1) + 16] = str16[(*((unsigned char*)&linkc + i)) >> 4]; md5str[(i << 1) + 17] = str16[(*((unsigned char*)&linkc + i)) & 0x0F]; md5str[(i << 1) + 24] = str16[(*((unsigned char*)&linkd + i)) >> 4]; md5str[(i << 1) + 25] = str16[(*((unsigned char*)&linkd + i)) & 0x0F]; } //最终MD5字符串结尾标志 md5str[32] = 0; } int main() { char md5str[33]; char str[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdabcdefghijklmnopqrst"; md5(str, sizeof(str), md5str); cout << md5str << endl; return 0; }