MD5 Program
根据老师的PPT讲解和RFC1321白皮书,我写了一个可执行的MD5加密程序。
Analysis
具体的思想为:
- 先逐个地接收信息字符,然后将每一个字符转化成长度为8位的阿斯克码二进制字符串,然后,加到现有的字符串中,当现有的字符串长度达到512bits时,对它进行处理,然后继续接收下一个512bits长度的字符串,直到最后一个字符输入,然后对最后一段做padding处理,留下最后64位作为长度记录。
- padding的时候有三种情况:现在的长度小于448,长度等于448,长度大于448,然后长度小于448的就直接补到448,长度等于或者大于448的就要补到下一个512分组的448位处,才能够把长度填入。
- 长度的填入是低位存在前32位,高位存在后32位。
- 把每一个512位的分组分成16个32位的无符号整数。之前我们传入的时候是按字符二进制传入的,现在把每四个字符的二进制字符串分为一组,按照小端规则变成16个无符号整数。
- 对每一个512位分组,按照下面的规则做4轮FGHI每轮16次迭代,得出这个分组后的结果:
具体的代码和实验结果如下:
Code
MD5.hpp
#ifndef MD5_HPP
#define MD5_HPP
class MD5
{
public:
MD5();
~MD5();
int SwitchIterationIndex(int i, int j);
unsigned int ShiftLeft(unsigned int in, int b);
void InitVector();
void InitShiftAmount();
void HMD5(unsigned int* in);
void MessageDealing(string s);
void PaddingDealing(string s);
unsigned int add(unsigned int a, unsigned int b);
unsigned int GBCD(int turn, unsigned int b, unsigned int c, unsigned int d);
void Print();
void GetXArray(string s);
private:
unsigned int input[4];
int s[64];
unsigned int x[16];
unsigned long long count;
};
#endif
MD5.cpp
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include "MD5.hpp"
using namespace std;
MD5::MD5() {
count = 0;
InitVector();
InitShiftAmount();
}
int MD5::SwitchIterationIndex(int i, int j) {
int f;
switch (i) {
case 0:
f = j;
break;
case 1:
f = (1 + 5 * j) % 16;
break;
case 2:
f = (5 + 3 * j) % 16;
break;
case 3:
f = (7 * j) % 16;
break;
}
return f;
}
unsigned int MD5::ShiftLeft(unsigned int in, int b) {
return (unsigned int)(((unsigned long long)in) << b) | (((unsigned long long)in) >> (32 - b));
}
void MD5::InitVector() {
input[0] = 0x67452301;
input[1] = 0xEFCDAB89;
input[2] = 0x98BADCFE;
input[3] = 0x10325476;
}
void MD5::HMD5(unsigned int* in) {
for (int k = 0; k < 4; k++) {
for (int q = 0; q < 16; q++) {
unsigned int tmps = add(GBCD(k, in[1], in[2], in[3]), in[0]);
unsigned int tmp1 = (unsigned int)floor(((unsigned long long)0x100000000)*abs(sin(k * 16 + q+1)));
tmps = add(tmps, x[SwitchIterationIndex(k,k*16+q)]);
tmps = add(tmps, tmp1);
tmp1 = ShiftLeft(tmps, s[k*16+q]);
tmps = tmp1 + in[1];
in[0] = in[3];
in[3] = in[2];
in[2] = in[1];
in[1] = tmps;
}
}
input[0] = input[0] + in[0];
input[1] = input[1] + in[1];
input[2] = input[2] + in[2];
input[3] = input[3] + in[3];
}
void MD5::GetXArray(string s) {
string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "";
for (int k = 0; k < 16; k++) {
tmp1 = s.substr(32 * k, 8);
tmp2 = s.substr(32 * k+8, 8);
tmp3 = s.substr(32 * k+16, 8);
tmp4 = s.substr(32 * k+24, 8);
x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
x[k] += strtol(tmp1.c_str(), NULL, 2);
}
}
void MD5::MessageDealing(string s) {
count += s.size();
string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "", another = "";
if (s.size() < 512) {
int a = s.size() % 512;
if (a == 448) {
s += "1";
for (int i = 1; i < 512; i++) {
s += "0";
}
another = s.substr(512,448);
GetXArray(s);
} else if (a < 448) {
s += "1";
for (int i = 0; i < (447 - a); i++) {
s += "0";
}
for (int k = 0; k < 14; k++) {
tmp1 = s.substr(32 * k, 8);
tmp2 = s.substr(32 * k+8, 8);
tmp3 = s.substr(32 * k+16, 8);
tmp4 = s.substr(32 * k+24, 8);
x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
x[k] += strtol(tmp1.c_str(), NULL, 2);
}
x[14] =(unsigned int)(count&(unsigned int)0xFFFFFFFF);
x[15] = (count>>32);
} else {
s += "1";
for (int i = 1; i < (960-a); i++) {
s += "0";
}
another = s.substr(512,448);
GetXArray(s);
}
} else {
GetXArray(s);
}
unsigned int temp[4];
for (int k = 0; k < 4; k++) {
temp[k] = input[k];
}
HMD5(temp);
if (s.size() > 512) PaddingDealing(another);
}
void MD5::PaddingDealing(string s) {
string tmp1 = "",tmp2 = "",tmp3 = "",tmp4 = "";
for (int k = 0; k < 14; k++) {
tmp1 = s.substr(32 * k, 8);
tmp2 = s.substr(32 * k+8, 8);
tmp3 = s.substr(32 * k+16, 8);
tmp4 = s.substr(32 * k+24, 8);
x[k] = strtol(tmp4.c_str(), NULL, 2) << 24;
x[k] += strtol(tmp3.c_str(), NULL, 2) << 16;
x[k] += strtol(tmp2.c_str(), NULL, 2) << 8;
x[k] += strtol(tmp1.c_str(), NULL, 2);
}
x[14] =(unsigned int)(count&(unsigned int)0xFFFFFFFF);
x[15] = (count>>32);
unsigned int temp[4];
for (int k = 0; k < 4; k++) {
temp[k] = input[k];
}
HMD5(temp);
}
unsigned int MD5::add(unsigned int a, unsigned int b) {
unsigned int c = 0xFFFFFFFF;
return (unsigned int)(((unsigned long)a + (unsigned long)b));
}
unsigned int MD5::GBCD(int turn, unsigned int b, unsigned int c, unsigned int d) {
unsigned int f;
switch (turn) {
case 0:
f = ((b)&(c)) | ((~b)&(d));
break;
case 1:
f = ((b)&(d)) | ((c)&(~d));
break;
case 2:
f = ((b)^(c) ^ (d));
break;
case 3:
f = ((c)^ ((b) | (~d)));
break;
}
return f;
}
void MD5::InitShiftAmount() {
s[0] = s[4] = s[8] = s[12] = 7;
s[1] = s[5] = s[9] = s[13] = 12;
s[2] = s[6] = s[10] = s[14] = 17;
s[3] = s[7] = s[11] = s[15] = 22;
s[16] = s[20] = s[24] = s[28] = 5;
s[17] = s[21] = s[25] = s[29] = 9;
s[18] = s[22] = s[26] = s[30] = 14;
s[19] = s[23] = s[27] = s[31] = 20;
s[32] = s[36] = s[40] = s[44] = 4;
s[33] = s[37] = s[41] = s[45] = 11;
s[34] = s[38] = s[42] = s[46] = 16;
s[35] = s[39] = s[43] = s[47] = 23;
s[48] = s[52] = s[56] = s[60] = 6;
s[49] = s[53] = s[57] = s[61] = 10;
s[50] = s[54] = s[58] = s[62] = 15;
s[51] = s[55] = s[59] = s[63] = 21;
}
void MD5::Print() {
unsigned int a = 0, b = 0, c = 0, d = 0;
for (int k = 0; k < 4; k++) {
a = input[k] & 0xFF;
a = a << 24;
b = input[k] & 0xFF00;
b = b << 8;
c = input[k] & 0xFF0000;
c = c >> 8;
d = input[k] & 0xFF000000;
d = d >> 24;
input[k] = a + b + c + d;
cout<<hex <<setfill('0')<<setw(8)<< input[k];
}
cout << endl;
}
MD5::~MD5() {}
test.cpp
#include "MD5.hpp"
using namespace std;
string Encode(char c) {
int num = (int)c;
int temp = 0;
string result = "";
for (int i = 7; i >= 0; i--) {
temp = num >> i;
if (temp % 2 == 0) {
result += "0";
} else {
result += "1";
}
}
return result;
}
int main() {
MD5* md = new MD5();
string s = "";
char c;
cout << "Please enter the infomation you want to encode and stop by enter ctrl + Z: " << endl;
int count = 0;
string str = "MD5 for(\"";
while (scanf("%c",&c) != EOF) {
str += c;
if (count == 64) {
count = 1;
md->MessageDealing(s);
s = "" + Encode(c);
} else {
s += Encode(c);
count++;
}
}
if (str.size() != 9) str = str.substr(0,str.size()-1);
s =s.substr(0,s.size()-8);
md->MessageDealing(s);
str += "\"): ";
cout << str;
md->Print();
delete md;
return 0;
}
实验结果截图
- Case 1
输入空字符串
结果为d41d8cd98f00b204e9800998ecf8427e - Case 2
输入”a”
结果为:0cc175b9c0f1b6a831c399e269772661 - Case 3
输入”abc”
结果为:900150983cd24fb0d6963f7d28e17f72 - Case 4
输入”message digest”
结果为:f96b697d7cb7938d525a2f31aaf161d0 - Case 5
输入”abcdefghijklmnopqrstuvwxyz”
结果为:c3fcd3d76192e4007dfb496cca67e13b
6.Case 6
输入”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789”
结果为:d174ab98d277d9f5a5611c2c9f419d9f
7.Case 7
输入”12345678901234567890123456789012345678901234567890123456789012345678901234567890”
结果为:57edf4a22be3c955ac49da2e2107b67a
与RFC321白皮书中提到的example一致:
MD5 For Password Protection
MD5特性
- 因为MD5是把信息转换成一个固定长度的密文,不管明文的长度是多少,密文的长度固定是128位,这样第一点就可以隐藏密码的具体长度。
- 第二个特性就是,MD5是不可逆的,具有单向性,就是说,只有密文,攻击者是无法得知明文的,所以这样来说,密码就比较安全,只有持有者才知道。
- 第三个就是,虽然MD5不是足够安全的,但是很难找到真正不同的两个消息,使得他们的MD5值相同。
MD5在密码中的应用
- 因为密码是检验密码持有者身份的依据,只要verifier知道这个身份是真是假就可以了。所以,verifier(一个公司、网站或其他服务提供商)在将MD5应用于密码校验的时候只需要将密码持有者送来的待校验密码用MD5算法处理,处理后将得到的MD5值与他们数据库中的存储的MD5值进行对比,如果一致,说明验证成功,如果不一致,说明校验失败。最原始的真正的密码在一开始注册的时候就被以MD5的形式存在数据库中。
- 以MD5的形式存在于验证方的数据库中,比裸密码要安全得多,因为攻击者如果得到数据库中的信息,要攻破MD5把原来的密码算出来是很困难的,所以相较之要安全很多。
- 一般的密码其实都可以用MD5加密,用户名也是可以的(或者说,也是很有必要的),只有当用户名和密码同时校验成功才算是校验成功。
本文介绍了一种基于MD5算法的加密程序实现方法,并详细解释了其工作流程和技术细节。通过对输入信息进行预处理、分组及多轮迭代运算等步骤,最终生成固定长度的密文。
2875

被折叠的 条评论
为什么被折叠?



