MD5 c++ 实现
最近实现MD5算法,发现最头疼的地方是对调试难以下手。众所周知,MD5算法,只要输入信息有一丝差别,结果就千差万别,而且MD5算法原理并不难,实现的过程最头疼的是细节,所以在此提供已实现完整功能的代码及标注调试位置,方便大家调试。
ps 本文不对MD5算法进行描述,因为一般都要开发说明,或者可以搜索 “RFC 1321”,这个是MD5的标准说明,本文使用的检验例子也来源于此,不过其内容有点多且乱,可另寻他处。
结果运行
首先为大家验证结果,证明本程序的可靠性:
测试例子,来源:RFC 1321
运行结果:
读者也可先获取代码,修改一下main函数,计算任意字符串的MD5,与网上的MD5加密工具结果进行对比
完整源码:MD5 代码(笔者GitHub)
以下为两个关键函数,思路和debug部分已注释好,读者可自行使用。算法涉及的小端模式,可参考大端模式和小端模式详解
信息流读取函数
/*
信息读取函数使用一种比较耗内存,但很容易写的方法来实现:
1)定义一个非常大的数组
2)将所有元素按顺序输入数组
3)读取,填充和加入信息长度这些步骤全部完成后,将数组赋值给M[16],每16个就push到MessageFlow中(16*32 = 512)
为何要使用大数组?使用大数组,你就不需要考虑当前的信息是否要push,可以节省代码,也可以减少if语句,降低程序的
复杂性。
*/
void MD5::read(string str)
{
unsigned int big_temp[1000] = {0};
unsigned int sub_index = 0;
unsigned int temp;
big_temp[sub_index] = 0;
int i;
long long int count = str.length() * 8;
for (i = 0; i < str.length(); i++)//transfer message
{
temp = str[i];
big_temp[sub_index] += temp << ((i % 4) * 8);
if (i % 4 == 3)
sub_index++;
}
temp = 0x80;//padding
big_temp[sub_index] += temp << ((i % 4) * 8);
if (i % 4 == 3)
sub_index++;
i++;
temp = 0x00;
while ((i * 8) % 512 != 448)
{
big_temp[sub_index] += temp << ((i % 4) * 8);
if (i % 4 == 3)
sub_index++;
i++;
}
big_temp[sub_index++] = (count << 32) >> 32;
big_temp[sub_index] = count >> 32;
unsigned int * M;
for (int i = 0; i <= sub_index; i++)//add message block to MessageFlow
{
if (i % 16 == 0)
{
M = new unsigned int[16];
}
else if (i % 16 == 15)
{
MessageFlow.push_back(M);
}
M[i % 16] = big_temp[i];
}
/*
此处用于将输入的信息print出来,主要验证“小端存储”操作是否出现错误。
for (int i = 0; i < MessageFlow.size(); i++)
{
for (int j = 0; j < 16; j++)
{
printf("%x ", MessageFlow[i][j]);
}
cout << endl;
}
*/
}
循环压缩函数:
void MD5::HMD5(int q)
{
unsigned int a, b, c, d;
a = A;
b = B;
c = C;
d = D;
unsigned int temp;
unsigned int X, sub_index;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 16; j++)
{
sub_index = i * 16 + j;
X = MessageFlow[q][index[sub_index]];
temp = a + g2(i, b, c, d) + X + T[sub_index];
/*
此处输出的是官方给的数据的输出,验证数据是否出错,注:T虽然可以临时计算,但我看很多例子
和官方代码都是使用现成的T值,且我尝试过直接算,一开始结果还是对的,到后面错了很多,因此建议
将T存入数组,直接使用就好。
cout << index[sub_index] << " " << T[sub_index] << " " << s[sub_index] << endl;
*/
temp = (temp << s[sub_index]) | (temp >> (32 - s[sub_index]));
a = b + temp;
/*
此处用于输出a,若a输出正确,说明以上步骤都是正确的。
printf("%x\n",a);
*/
temp = d;
d = c;
c = b;
b = a;
a = temp;
}
}
A = A + a;
B = B + b;
C = C + c;
D = D + d;
}