此算法使用C++写成。更多详细内容可参考GitHub项目
①填充字符串函数:在长度为K bits的原始消息尾部填充长度为P bits的标识(1000…00),其中1 <= P <= 512(即至少需要填充一个bit),使得填充后的消息位数为 K+P ≡ 448(mod 512)。注意,当K ≡ 448(mod 512)时,填充的字节数 P = 512 bit。填充得到上述消息后,在尾部附加K值的低64位,最后得到一个长度为 K+P+64 ≡ 0(mod 512)的消息。
②字符串分块函数:将填充好的字符串分割成L个长度为512bit的分组
③循环压缩函数:对每个512-bit分组进行64轮迭代运算
(1)对分组(A,B,C,D)中的A进行迭代运算
公式为:A <= B + ((A + g(B,C,D) + X[k] + T[i])) << S[i]
其中:
· A,B,C,D代表MD5缓冲区当前的数值
· g为轮函数,1-16轮迭代使用F函数,17-32轮迭代使用G函数,33-48轮迭 代使用H函数,49-64轮迭代使用I函数
· X[k]代表当前处理消息分组的第k个32位字,X[k]由第n轮迭代对应的顺序表决定
· T[i]代表T表的第i项的值,T[i] = int(2^32 * |sin(i)|)
· S[i]对应第i轮的左循环移位的s值
(2)对分组(A,B,C,D)作循环轮换
公式为:(B,C,D,A)<=(A,B,C,D)
④MD5编码函数:用于调用前面的功能函数进行MD5编码
(1)输入待加密的明文字符串
(2)对明文字符串进行填充
(3)对填充后的明文字符串进行分块(Yq)
(4)使用预设的初始值初始化MD5缓冲区间(IV)
(5)对各个分块字符串利用公式HMD5(CVi-1, Yi)进行循环压缩,运算结果作为下一块的输入(CVi)
当所有的分块迭代完成后,输出结果CVL,L表示最后一个分块的序号
#include
#include
#include
#include
using namespace std;
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
const char str16[] = "0123456789abcdef";
const unsigned int T[] = {
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 s[] = { 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};
class MD5 {
private:
unsigned int tempA, tempB, tempC, tempD, strlength;
public:
MD5() {
tempA = A;
tempB = B;
tempC = C;
tempD = D;
strlength = 0;
}
// F函数
unsigned int F(unsigned int b, unsigned int c, unsigned int d) {
return (b & c) | ((~b) & d);
}
// G函数
unsigned int G(unsigned int b, unsigned int c, unsigned int d) {
return (b & d) | (c & (~d));
}
// H函数
unsigned int H(unsigned int b, unsigned int c, unsigned int d) {
return b ^ c ^ d;
}
// I函数
unsigned int I(unsigned int b, unsigned int c, unsigned int d) {
return c ^ (b | (~d));
}
// 移位操作函数
unsigned int shift(unsigned int a, unsigned int n) {
return (a << n) | (a >> (32 - n));
}
// 编码函数
string encode(string src) {
vector<unsigned int> rec = padding(src);
for(unsigned int i = 0; i < strlength/16; i++) {
unsigned int num[16];
for(int j = 0; j < 16; j++) {
num[j] = rec[i*16+j];
}
iterateFunc(num, 16);
}
return format(tempA) + format(tempB) + format(tempC) + format(tempD);
}
// 循环压缩
void iterateFunc(unsigned int* X, int size = 16) {
unsigned int a = tempA,
b = tempB,
c = tempC,
d = tempD,
rec = 0,
g, k;
for(int i = 0; i < 64; i++) {
if(i < 16) {
// F迭代
g = F(b, c, d);
k = i;
}
else if(i < 32) {
// G迭代
g = G(b, c, d);
k = (1 + 5*i) % 16;
}
else if(i < 48) {
// H迭代
g = H(b, c, d);
k = (5 + 3*i) % 16;
}
else {
// I迭代
g = I(b, c, d);
k = (7*i) % 16;
}
rec = d;
d = c;
c = b;
b = b + shift(a + g + X[k] + T[i], s[i]);
a = rec;
}
tempA += a;
tempB += b;
tempC += c;
tempD += d;
}
// 填充字符串
vector<unsigned int> padding(string src) {
// 以512位,64个字节为一组
unsigned int num = ((src.length() + 8) / 64) + 1;
vector<unsigned int> rec(num*16);
strlength = num*16;
for(unsigned int i = 0; i < src.length(); i++){
// 一个unsigned int对应4个字节,保存4个字符信息
rec[i>>2] |= (int)(src[i]) << ((i % 4) * 8);
}
// 补充1000...000
rec[src.length() >> 2] |= (0x80 << ((src.length() % 4)*8));
// 填充原文长度
rec[rec.size()-2] = (src.length() << 3);
return rec;
}
// 整理输出
string format(unsigned int num) {
string res = "";
unsigned int base = 1 << 8;
for(int i = 0; i < 4; i++) {
string tmp = "";
unsigned int b = (num >> (i * 8)) % base & 0xff;
for(int j = 0; j < 2; j++) {
tmp = str16[b%16] + tmp;
b /= 16;
}
res += tmp;
}
return res;
}
};
int main() {
MD5 test;
string a = "";
cout << "Plain Text: ";
getline(cin,a);
cout << "result: " << test.encode(a) << endl;
}