#include<iostream>
#include<string>
using namespace std;
//主循环使用的函数
#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 leftrotate(x,n) (((x)<<(n))|((x)>>(32-n)))
//初始哈希值
const unsigned int h0 = 0x67452301;
const unsigned int h1 = 0xEFCDAB89;
const unsigned int h2 = 0x98BADCFE;
const unsigned int h3 = 0x10325476;
//常数表
const int k[64] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8,
0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51,
0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905,
0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681,
0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60,
0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314,
0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
//左移表
const unsigned int 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
};
//512bits大小的块的数目
unsigned int chunk_num;
//填充函数
unsigned int* add(string input){
/*一个char型大小是1Byte,也就是8bits,
因此用(长度*8+64/512)就是加了长度信息后未填充的时候的块数目,
填充后就是(长度*8+64/512)+1
填充的信息量是(chunk_num*512-长度*8)bits
*/
chunk_num = ((input.length()*8 + 64) / 512) + 1;
//一个无符号整型存放32bits(4Bytes)的信息,512/32 = 16,所以需要chunk_num*16个
unsigned int *inputByte = new unsigned int[chunk_num * 16];
//初始化全填0,可以省去填充时在尾部加一个1后填充0的步骤
for (int i = 0; i < chunk_num * 16; i++){
inputByte[i] = 0;
}
//把输入信息转化为无符号整型存放在数组中
for (unsigned int i = 0; i < input.length(); i++){
/*一个字符8bits,因此4个字符才能填满一个无符号整型
存放使用小端规则(低低,高高)存放,
例如(字符串低位)(1000 0001)(1000 0011)(1000 0111)(1000 1111)(字符串的高位)
存放进去是(整数的高位)(1000 1111)(1000 0111)(1000 0011)(1000 0001)(整数的低位)
*/
inputByte[i / 4] += (input[i]) << ((i % 4) * 8);
}
//填充一个1,1000 0000 -> 0x80
inputByte[input.length() / 4] += 0x80 << ((input.length() % 4) * 8);
/*
*添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
*/
inputByte[chunk_num * 16 - 2] = input.length() * 8;
return inputByte;
}
//把大端规则存放的哈希值转换回小端规则
string hex_to_string(unsigned int h){
unsigned int temp;
string str;
string str_temp;
for (int i = 0; i < 4; i++){
str_temp = "";
//每次找出8bits
temp = ((h >> (i * 8)) % (1 << 8)) & 0xff;
for (int j = 0; j < 2; j++){
char c;
//把这8bits从整型转换成字符
if (temp % 16 > 9){
c = (char)(65 + ((temp % 16) - 10));
}
else{
c = (char)(48 + (temp % 16));
}
//例如AB先转换出的顺序是B,A,因此要插在前头
str_temp.insert(0, 1, c);
temp /= 16;
}
str += str_temp;
}
return str;
}
//获得MD5的核心函数
string getMD5(string input){
//填充后获得块
unsigned int* chunk = add(input);
unsigned int temph0 = h0;
unsigned int temph1 = h1;
unsigned int temph2 = h2;
unsigned int temph3 = h3;
for (int i = 0; i < chunk_num; i++){
/*总共有chunk[chunk_num*16]
每次处理16个chunk,16个chunk是一个512块
*/
unsigned int a = temph0;
unsigned int b = temph1;
unsigned int c = temph2;
unsigned int d = temph3;
unsigned int f;
unsigned int g;
for (int j = 0; j < 64; j++){
if (j < 16){
f = F(b, c, d);
g = j;
}
else if (j < 32){
f = G(b,c,d);
g = (5 * j + 1) % 16;
}
else if (j < 48){
f = H(b, c, d);
g = (3 * j + 5) % 16;
}
else{
f = I(b, c, d);
g = (7 * j) % 16;
}
unsigned int temp = d;
d = c;
c = b;
//每次处理16个块,所以是i*16+g
b = leftrotate((a + f + k[j] + chunk[i*16+g]), r[j]) + b;
a = temp;
}
temph0 += a;
temph1 += b;
temph2 += c;
temph3 += d;
}
//获得MD5码
string ans = hex_to_string(temph0) + hex_to_string(temph1) + hex_to_string(temph2) + hex_to_string(temph3);
return ans;
}
int main(){
string ss[7] = {
"",
"a",
"abc",
"message digest",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
"8a683566bcc7801226b3d8b0cf35fd97"
};
/*
测试数据应该得到的md5码
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") = f29939a25efabaef3b87e2cbfe641315
MD5 ("8a683566bcc7801226b3d8b0cf35fd97") =cf2cb5c89c5e5eeebef4a76becddfcfd
*/
for (int i = 0; i < 7; i++){
cout << "加密的字符串:" << ss[i] << endl;
cout << "MD5码:" << getMD5(ss[i]) << endl;
}
return 0;
}