很久之前就对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 ~