信息安全技术 || c++实现MD5

MD5算法简介:

消息摘要算法第五版(英语:Message-Digest Algorithm 5,缩写为MD5),是当前计算机领域用于确保信息传输完整一致而广泛使用的散列算法之一(又译哈希算法、摘要算法等),主流编程语言普遍已有MD5的实现。将数据 (如一段文字)运算变为另一固定长度值,是散列算法的基础原理,MD5的前身有MD2、MD3和MD4。MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。目前,MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通 数据的错误检查领域。例如在一些BitTorrent下载中,软件将通过计算MD5检验下载到的文件片段的完整性。MD5已经广泛使用在为文件传输提供一定的可靠性方面。例如,服务器预先提供一个MD5校验和,用户下载完文件以后, 用MD5算法计算下载文件的MD5校验和,然后通过检查这两个校验和是否一致,就能判断下载的文件是否出错。MD5是输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个 128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

MD5运算步骤:

假设输入信息(input message)的长度为b(bit),我们想要产生它的报文摘要,在此处b为任意的非负整数:b也可能为0,也不一定为8的整数倍,且可能是任意大的长度。设该信息的比特流表示如下: M[0] M[1] M[2] … M[b-1] 计算此信息的报文摘要需要如下5步:

1.补位

信息计算前先要进行位补位,设补位后信息的长度为LEN(bit),则LEN%512 = 448(bit),即数据扩展至 K * 512 + 448(bit)。即K * 64+56(byte),K为整数。补位操作始终要执行,即使补位前信息的长度对512求余的结果是448。具体补位操作:补一个1,然后补0至满足上述要求。总共最少要补1bit,最多补512bit。

2.尾部加上信息长度

将输入信息的原始长度b(bit)表示成一个64-bit的数字,把它添加到上一步的结果后面(在32位的机器上,这64位将用2个字来表示并且低位在前)。当遇到b大于2^64这种极少的情况时,b的高位被截去,仅使用b的低64位。经过上面两步,数据就被填补成长度为512(bit)的倍数。也就是说,此时的数据长度是16个字(32byte)的整数倍。此时的数据表示为: M[0 … N-1] 其中的N是16的倍数。

3.初始化缓存区

用一个四个字的缓冲器(A,B,C,D)来计算报文摘要,A,B,C,D分别是32位的寄存器,初始化使用的是十六进制表示的数字,注意低字节在前: word A: 01 23 45 67 word B: 89 ab cd ef word C: fe dc ba 98 word D: 76 54 32 10

A = 0x67452301;
B = 0xEFCDAB89;
C = 0x98BADCFE;
D = 0x10325476;

4.转换

四轮循环运算:循环的次数是分组的个数(N+1):

1)将每一512字节细分成16个小组,每个小组64位(8个字节)

2)用到的作为辅助的四个线性函数

unsigned int F(unsigned int x, unsigned int y, unsigned int z) {
	return (x & y) | ((~x) & z);
}

unsigned int G(unsigned int x, unsigned int y, unsigned int z) {
	return (x & z) | (y & (~z));
}

unsigned int H(unsigned int x, unsigned int y, unsigned int z) {
	return x ^ y ^ z;
}

unsigned int I(unsigned int x, unsigned int y, unsigned int z) {
	return y ^ (x | (~z));
}

3)x表示消息的某个子分组(从0到15),<<

unsigned int FF(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, int s, unsigned int ac) {
	a += F(b, c, d) + x + ac;
	a = (a << s) | (a >> (32 - s));
	a += b;
	return a;
}

unsigned int GG(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, int s, unsigned int ac) {
	a += G(b, c, d) + x + ac;
	a = (a << s) | (a >> (32 - s));
	a += b;
	return a;
}

unsigned int HH(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, int s, unsigned int ac) {
	a += H(b, c, d) + x + ac;
	a = (a << s) | (a >> (32 - s));
	a += b;
	return a;
}

unsigned int II(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int x, int s, unsigned int ac) {
	a += I(b, c, d) + x + ac;
	a = (a << s) | (a >> (32 - s));
	a += b;
	return a;
}

4)四轮运算

void MD5::transform(const unsigned char *block) {
	unsigned int a = A, b = B, c = C, d = D;
	unsigned int groups[16];
	decode(groups, block, 64);
	//groups[15] = 0;
	a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L); /* 1 */
    d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L); /* 2 */
    c = FF(c, d, a, b, groups[2], S13, 0x242070dbL); /* 3 */
    b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL); /* 4 */
    a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL); /* 5 */
    d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL); /* 6 */
    c = FF(c, d, a, b, groups[6], S13, 0xa8304613L); /* 7 */
    b = FF(b, c, d, a, groups[7], S14, 0xfd469501L); /* 8 */
    a = FF(a, b, c, d, groups[8], S11, 0x698098d8L); /* 9 */
    d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL); /* 10 */
    c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L); /* 11 */
    b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL); /* 12 */
    a = FF(a, b, c, d, groups[12], S11, 0x6b901122L); /* 13 */
    d = FF(d, a, b, c, groups[13], S12, 0xfd987193L); /* 14 */
    c = FF(c, d, a, b, groups[14], S13, 0xa679438eL); /* 15 */
    b = FF(b, c, d, a, groups[15], S14, 0x49b40821L); /* 16 */
    /*第二轮*/
    a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L); /* 17 */
    d = GG(d, a, b, c, groups[6], S22, 0xc040b340L); /* 18 */
    c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L); /* 19 */
    b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL); /* 20 */
    a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL); /* 21 */
    d = GG(d, a, b, c, groups[10], S22, 0x2441453L); /* 22 */
    c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L); /* 23 */
    b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L); /* 24 */
    a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L); /* 25 */
    d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L); /* 26 */
    c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L); /* 27 */
    b = GG(b, c, d, a, groups[8], S24, 0x455a14edL); /* 28 */
    a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L); /* 29 */
    d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L); /* 30 */
    c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L); /* 31 */
    b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL); /* 32 */

    /*第三轮*/
    a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L); /* 33 */
    d = HH(d, a, b, c, groups[8], S32, 0x8771f681L); /* 34 */
    c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L); /* 35 */
    b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL); /* 36 */
    a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L); /* 37 */
    d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L); /* 38 */
    c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L); /* 39 */
    b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L); /* 40 */
    a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L); /* 41 */
    d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL); /* 42 */
    c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L); /* 43 */
    b = HH(b, c, d, a, groups[6], S34, 0x4881d05L); /* 44 */
    a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L); /* 45 */
    d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L); /* 46 */
    c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L); /* 47 */
    b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L); /* 48 */

    /*第四轮*/
    a = II(a, b, c, d, groups[0], S41, 0xf4292244L); /* 49 */
    d = II(d, a, b, c, groups[7], S42, 0x432aff97L); /* 50 */
    c = II(c, d, a, b, groups[14], S43, 0xab9423a7L); /* 51 */
    b = II(b, c, d, a, groups[5], S44, 0xfc93a039L); /* 52 */
    a = II(a, b, c, d, groups[12], S41, 0x655b59c3L); /* 53 */
    d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L); /* 54 */
    c = II(c, d, a, b, groups[10], S43, 0xffeff47dL); /* 55 */
    b = II(b, c, d, a, groups[1], S44, 0x85845dd1L); /* 56 */
    a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL); /* 57 */
    d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L); /* 58 */
    c = II(c, d, a, b, groups[6], S43, 0xa3014314L); /* 59 */
    b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L); /* 60 */
    a = II(a, b, c, d, groups[4], S41, 0xf7537e82L); /* 61 */
    d = II(d, a, b, c, groups[11], S42, 0xbd3af235L); /* 62 */
    c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL); /* 63 */
    b = II(b, c, d, a, groups[9], S44, 0xeb86d391L); /* 64 */

	A += a;
    B += b;
    C += c;
    D += d;
}

函数中两个比较重要的模块,其中一个是update函数,也是大部分摘要算法都具有的操作:

作用主要是更新MD5块。然后继续MD5消息摘要操作,处理另一个消息块。

void MD5::update(const unsigned char *input, int length) {
	inputNum += (length << 3);
    int start = 64 - bufferNum;
    ////将输入的一部分复制到buffer所以它可以形成一个块(size = 64)
    if(start <= length)
    {
    	//可以形成一个块,然后对这个块做四轮循环
            memcpy(&buffer[bufferNum], input, start);
            transform(buffer);
            
            int i;
            for(i = start; i <= length - 64; i += 64)
            {
                transform(&input[i]);
            }
            bufferNum = length - i;  
            memcpy(buffer, &input[i], bufferNum);  
    }     
    else
    {
    	//不能形成块
        memcpy(&buffer[bufferNum], input, length);
        bufferNum += length;
    }    
}

然后再是Final函数,作用是使用100000填充buffer, 并添加64位原始大小的输入

void MD5::Final()
{
    int temp = 56 - bufferNum;  //56 = 448/8
    //填充
    if(temp > 0)
    {
        update(padding, temp);

        inputNum -= (temp << 3);
    }
    else if(temp < 0)
    {
        update(padding, 64 + temp);
        inputNum -= ((64 + temp) << 3);
    }
    //trans inputNum(输入的位数) to unsigned char (64bits)
    unsigned char Bits[8];
    //cout << inputNum << endl;
    for(int i = 0; i < 8; i++)
    {
    	//cout << inputNum << endl;
        Bits[i] = (inputNum >> 8*i) & 0xff;
        //cout << i << endl;
    }
    //cout << (int)Bits[4] << endl;
    //添加最初输入的num(后64位)
    update(Bits, 8); 
    unsigned int input[4];
    input[0] = A;
   	input[1] = B;
   	input[2] = C;
   	input[3] = D;
   	//将input存入result
    encode(result, input, 16);
}

最后将整个模块整合为类:

class MD5 {

private:
	string cipher;
	unsigned int A;
	unsigned int B;
	unsigned int C;
	unsigned int D;
	unsigned char buffer[64];
	int bufferNum;  //
	unsigned long long inputNum;
	unsigned char result[16];

public:
	MD5();
	~MD5();
	string encrypt(const char* fiename);

private:
	void readCipher(const char *filename);
	void update(const unsigned char *input, int length);
	void encode(unsigned char *output, unsigned int *input, int length);
	void decode(unsigned int *output, const unsigned char* input, const int length);
	void transform(const unsigned char *block);
	void Final();
};

运行结果:

将要加密的文本写入到密码本中:
在这里插入图片描述

运行结果:

在这里插入图片描述

然后与加密网站的结果进行对比:

网站为:http://tool.chinaz.com/tools/md5.aspx
在这里插入图片描述

结果一致,说明加密成功。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章