很久之前就对md5很好奇,抽空研究了一下,算法过程还是挺简单的,为什么是这个过程就不是我辈能参透的了。自己写了个c++版本的,希望对md5好奇的朋友们有帮助。
md5.h
#include <string> typedef unsigned int uint; class MD5 { public: MD5(); std::string md5(std::string str); uint turnhex(uint); private: uint m_k[64]; uint m_a; uint m_b; uint m_c; uint m_d; static uint m_r[64]; };
md5.cpp
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <iostream> #include "md5.h" using namespace std; uint MD5::m_r[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 }; MD5::MD5() { m_a = 0x67452301; m_b = 0xEFCDAB89; m_c = 0x98BADCFE; m_d = 0x10325476; for(int i = 0; i < 64; i++) { m_k[i] = 4294967296.0 * fabs(sin(i + 1)); } } string MD5::md5(string str) { int x = str.length() / 64; int y = str.length() % 64; int z; if(y > 56) { z = 64 * (x + 2); } else { z = 64 * (x + 1); } //上面计算出填充后的字节数z,然后开辟z字节的空间 void *tmp = malloc(z); memset(tmp, 0, z); strcpy((char *)tmp, str.c_str()); //在原字符串后第一个bit加个1然后若干个0,这里是指的都是bit *((unsigned char *)tmp + str.length()) = (unsigned char)(0x1 << 7); //转成uint型数据,在下面的循环计算中使用,z /= 4后即uint型数组w的大小 uint *w = (uint *)tmp; z /= 4; //在数组的最后两位用以64位数据记录原字符串的bit长度 *((unsigned __int64 *)(w) + z / 2 - 1) = str.length() * 8; uint h0 = m_a; uint h1 = m_b; uint h2 = m_c; uint h3 = m_d; //对w数组每16个数据为一段,进行一次计算 for(int k = 0; k < z; k += 16) { uint a = h0; uint b = h1; uint c = h2; uint d = h3; for(int i = 0; i < 64; i++) { uint f, g; if(i < 16) { f = b & c | ~b & d; g = i; } else if(i < 32) { f = d & b | ~d & c; g = (5 * i + 1) % 16; } else if(i < 48) { f = b ^ c ^ d; g = (3 * i + 5) % 16; } else { f = c ^ (b | ~d); g = (7 * i) % 16; } //对于每个a,b,c,d通过计算得到temp uint temp = a + f + w[k + g] + m_k[i]; temp = (temp << m_r[i] | temp >> (32 - m_r[i])) + b; //下面可以理解成先a = temp //然后a,b,c,d的循环换一下位置作为下一次计算的初值 a = d; d = c; c = b; b = temp; } h0 += a; h1 += b; h2 += c; h3 += d; } free(tmp); char md5_str[33]; sprintf(md5_str, "%08x%08x%08x%08x", turnhex(h0), turnhex(h1), \ turnhex(h2), turnhex(h3)); return md5_str; } uint MD5::turnhex(uint hex) { uint ret = hex & 0xff; ret = ret << 8 | hex >> 8 & 0xff; ret = ret << 8 | hex >> 16 & 0xff; ret = ret << 8 | hex >> 24 & 0xff; return ret; } int main() { MD5 md5; string str; while(cin >> str) { cout << md5.md5(str) << endl; } return 0; }
代码简要说明:
MD5::MD5();
对加密算法中每次都使用到的变量m_k[i], m_a, m_b, m_c, m_d进行初始化
uint MD5::turnhex(uint hex);
如果hex = 0xaabbccdd;则turnhex(hex) == 0xddccbbaa;
unsigned __int64
如果编译器不支持可以换成unsigned long long
参考资料:
几年前写过一个用wxwidget库做界面的,不过用的是des算法,似乎比你的复杂一点
des and md5 are different ~