C++ MD5

MD5是一种摘要算法,通过压缩+加密+hash的算法是绝对不可逆的。网上有很多人都写了,我也参考了MD5的基本规则写的。这个算法从数学角度上来说,主要是需要证明唯一性,但凭我等的能力想要做这种证明是不太现实的。因为我实在没办法去证明通过一系列的运算,累加a,b,c,d还能够有唯一性,因为就逆向去看加法,那是有无数解的,MD5也只能说在概率上是不会重复的吧。所以说那个幻数,还有里面的那些数据,是不能轻易改的吧,稍微量变,加法可能就会发生质变,导致多种映射指向到同一结果。不过就hash来说,512位 64个字节,通过一系列运算使得有大于64^256种唯一映射还是有可能去证明的。我自己重新写了下MD5算法,写得逻辑更清晰,看着很舒服的。


两个工具方法:

uchar* longTouchar(long n)
{
	uchar* b = new uchar[4];
	for (int i = 3; i >= 0; --i)
	{
		b[i] = n >> i * 8;
	}
	return b;
}

std::string getHexStr(uchar* val, int length)
{
	std::stringstream ss;
	char characterArray[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
	for (int i = 0; i<length; ++i)
	{
		ss << characterArray[val[i] / 16] << characterArray[val[i] % 16];;
	}
	return ss.str();
}

md5.h

#pragma once
class md5
{
	const uint A = 0x67452301L;
	const uint B = 0xEFCDAB89L;
	const uint C = 0x98badcfe;
	const uint D = 0x10325476;

	uint F(uint x, uint y, uint z);
	uint G(uint x, uint y, uint z);
	uint H(uint x, uint y, uint z);
	uint I(uint x, uint y, uint z);


	void FF(uint& a, uint b, uint c, uint d, uint src, uint s, uint m);
	void GG(uint& a, uint b, uint c, uint d, uint src, uint s, uint m);
	void HH(uint& a, uint b, uint c, uint d, uint src, uint s, uint m);
	void II(uint& a, uint b, uint c, uint d, uint src, uint s, uint m);

	uint LeftMoveLoop(uint n, uint s);
	uchar* buf;
	uint virtualVals[4];
	void Process();
	uint* spTouintArray();

public:
	md5(uchar* str, int size);
	uchar* getResult();
};


#include"stdafx.h"
#include "md5.h"
uint md5::F(uint x, uint y, uint z)
{
	return (x&y) | ((~x)&z);
}

uint md5::G(uint x, uint y, uint z)
{
	return (x&z) | (y&(~z));
}

uint md5::H(uint x, uint y, uint z)
{
	return x^y^z;
}

uint md5::I(uint x, uint y, uint z)
{
	return y ^ (x | (~z));
}

void md5::FF(uint& a, uint b, uint c, uint d, uint src, uint s, uint m)
{
	a = b + LeftMoveLoop(a + F(b, c, d) + src + m, s);
}

void md5::GG(uint& a, uint b, uint c, uint d, uint src, uint s, uint m)
{
	a = b + LeftMoveLoop(a + G(b, c, d) + src + m, s);
}

void md5::HH(uint& a, uint b, uint c, uint d, uint src, uint s, uint m)
{
	a = b + LeftMoveLoop(a + H(b, c, d) + src + m, s);
}

void md5::II(uint& a, uint b, uint c, uint d, uint src, uint s, uint m)
{
	a = b + LeftMoveLoop(a + I(b, c, d) + src + m, s);
}


uint md5::LeftMoveLoop(uint n, uint s)
{
	return (n << s) | (n >> (32 - s));
}


unsigned* md5::spTouintArray()
{
	uint* a = new uint[16];
	for (int i = 0; i<16; ++i)
	{
		uint a1 = buf[i * 4];
		uint a2 = buf[i * 4 + 1];
		uint a3 = buf[i * 4 + 2];
		uint a4 = buf[i * 4 + 3];
		a[i] = a1 | a2 << 8 | a3 << 16 | a4 << 24;
	}
	return a;
}

void md5::Process()
{
	uint a = virtualVals[0], b = virtualVals[1], c = virtualVals[2], d = virtualVals[3];
	uint* M = spTouintArray();

	FF(a, b, c, d, M[0], 7, 0xd76aa478);
	FF(d, a, b, c, M[1], 12, 0xe8c7b756);
	FF(c, d, a, b, M[2], 17, 0x242070db);
	FF(b, c, d, a, M[3], 22, 0xc1bdceee);
	FF(a, b, c, d, M[4], 7, 0xf57c0faf);
	FF(d, a, b, c, M[5], 12, 0x4787c62a);
	FF(c, d, a, b, M[6], 17, 0xa8304613);
	FF(b, c, d, a, M[7], 22, 0xfd469501);
	FF(a, b, c, d, M[8], 7, 0x698098d8);
	FF(d, a, b, c, M[9], 12, 0x8b44f7af);
	FF(c, d, a, b, M[10], 17, 0xffff5bb1);
	FF(b, c, d, a, M[11], 22, 0x895cd7be);
	FF(a, b, c, d, M[12], 7, 0x6b901122);
	FF(d, a, b, c, M[13], 12, 0xfd987193);
	FF(c, d, a, b, M[14], 17, 0xa679438e);
	FF(b, c, d, a, M[15], 22, 0x49b40821);

	GG(a, b, c, d, M[1], 5, 0xf61e2562);
	GG(d, a, b, c, M[6], 9, 0xc040b340);
	GG(c, d, a, b, M[11], 14, 0x265e5a51);
	GG(b, c, d, a, M[0], 20, 0xe9b6c7aa);
	GG(a, b, c, d, M[5], 5, 0xd62f105d);
	GG(d, a, b, c, M[10], 9, 0x2441453);
	GG(c, d, a, b, M[15], 14, 0xd8a1e681);
	GG(b, c, d, a, M[4], 20, 0xe7d3fbc8);
	GG(a, b, c, d, M[9], 5, 0x21e1cde6);
	GG(d, a, b, c, M[14], 9, 0xc33707d6);
	GG(c, d, a, b, M[3], 14, 0xf4d50d87);
	GG(b, c, d, a, M[8], 20, 0x455a14ed);
	GG(a, b, c, d, M[13], 5, 0xa9e3e905);
	GG(d, a, b, c, M[2], 9, 0xfcefa3f8);
	GG(c, d, a, b, M[7], 14, 0x676f02d9);
	GG(b, c, d, a, M[12], 20, 0x8d2a4c8a);

	HH(a, b, c, d, M[5], 4, 0xfffa3942);
	HH(d, a, b, c, M[8], 11, 0x8771f681);
	HH(c, d, a, b, M[11], 16, 0x6d9d6122);
	HH(b, c, d, a, M[14], 23, 0xfde5380c);
	HH(a, b, c, d, M[1], 4, 0xa4beea44);
	HH(d, a, b, c, M[4], 11, 0x4bdecfa9);
	HH(c, d, a, b, M[7], 16, 0xf6bb4b60);
	HH(b, c, d, a, M[10], 23, 0xbebfbc70);
	HH(a, b, c, d, M[13], 4, 0x289b7ec6);
	HH(d, a, b, c, M[0], 11, 0xeaa127fa);
	HH(c, d, a, b, M[3], 16, 0xd4ef3085);
	HH(b, c, d, a, M[6], 23, 0x4881d05);
	HH(a, b, c, d, M[9], 4, 0xd9d4d039);
	HH(d, a, b, c, M[12], 11, 0xe6db99e5);
	HH(c, d, a, b, M[15], 16, 0x1fa27cf8);
	HH(b, c, d, a, M[2], 23, 0xc4ac5665);

	II(a, b, c, d, M[0], 6, 0xf4292244);
	II(d, a, b, c, M[7], 10, 0x432aff97);
	II(c, d, a, b, M[14], 15, 0xab9423a7);
	II(b, c, d, a, M[5], 21, 0xfc93a039);
	II(a, b, c, d, M[12], 6, 0x655b59c3);
	II(d, a, b, c, M[3], 10, 0x8f0ccc92);
	II(c, d, a, b, M[10], 15, 0xffeff47d);
	II(b, c, d, a, M[1], 21, 0x85845dd1);
	II(a, b, c, d, M[8], 6, 0x6fa87e4f);
	II(d, a, b, c, M[15], 10, 0xfe2ce6e0);
	II(c, d, a, b, M[6], 15, 0xa3014314);
	II(b, c, d, a, M[13], 21, 0x4e0811a1);
	II(a, b, c, d, M[4], 6, 0xf7537e82);
	II(d, a, b, c, M[11], 10, 0xbd3af235);
	II(c, d, a, b, M[2], 15, 0x2ad7d2bb);
	II(b, c, d, a, M[9], 21, 0xeb86d391);


	virtualVals[0] += a;
	virtualVals[1] += b;
	virtualVals[2] += c;
	virtualVals[3] += d;

	delete buf;
	delete M;
}

md5::md5(uchar* str, int size)
{
	virtualVals[0] = A;
	virtualVals[1] = B;
	virtualVals[2] = C;
	virtualVals[3] = D;

	int oriSize = size;
	int counter = 0;
	bool needAddEnd = true;
	while(true)
	{
		buf = new uchar[64];//在Process后自动释放
		int cpyLen = size - counter;
		if(cpyLen>64)
		{
			cpyLen = 64;
		}
		if(size>=56)//只要大于等于56,就意味着无法同时写下8+64位,结束的情况一定是写下oriSize
		{
			memcpy(buf, str+counter, cpyLen);//先行拷贝
			size -= cpyLen;
			counter += cpyLen;
			if(cpyLen==64)
			{
				Process();
				continue;
			}
			buf[cpyLen] = 128;//0x10000000
			memset(buf + cpyLen + 1, 0, 64 - cpyLen - 1);//剩余全部填充0
			needAddEnd = false;
			Process();
		}
		else
		{
			if (needAddEnd) {
				memcpy(buf, str + counter, size);//拷贝剩余字节
				buf[size] = 128;//0x10000000
				memset(buf + size + 1, 0, 64 - size - 1);//剩余全部填充0
			}
			else
			{
				memset(buf, 0, 64);//在前一项已经填充过0,证明一定填充过0x10000000,所以这就只用填充0
			}
			uchar* ucSize = longTouchar(oriSize*(long)8);
			//将int复制到buf上最后8个字节上去
			memcpy(buf + 56, ucSize, 4);
			delete ucSize;
			Process();
			break;
		}
	}
}

uchar* md5::getResult()
{
	uchar* ret = new uchar[16];
	for(int i=0;i<4;++i)
	{
		memcpy(ret+i*4, longTouchar(virtualVals[i]), 4);
	}
	return ret;
}





调用

md5 m5((uchar*)pwd, strlen(pwd));
	uchar* pmd5 = m5.getResult();
	cout << getHexStr(pmd5, 16)<<endl;
	


猜你喜欢

转载自blog.csdn.net/nightwizard2030/article/details/78508483