MD5 C++实现版

MD5

Posted by SixTeen on October 30, 2015
#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;
}
1
Fin 10.30/23:45