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
#include <string>
#include <sstream>
#define uchar unsigned char
#define uint unsigned int
uchar* longTouchar(long n);
std::string getHexStr(uchar* val, int length);
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();
uint offset;
uint totalLen;
public:
md5(uint totalLen);
uchar* getResult();
void update(uchar* str, int size, bool isEnd);
};
#include "md5.h"
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();
}
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;
buf = 0;
}
void md5::update(uchar* str, int size,bool isEnd) {
int counter = 0;
bool needAddEnd = true;
while (true)
{
if (buf == 0) {
buf = new uchar[64];//在Process后自动释放
offset = 0;
}
int surplusLen = 64 - offset;
if (isEnd) {
int cpyLen = size;
if (cpyLen > surplusLen)
{
cpyLen = surplusLen;
}
if (size >= surplusLen-8)//只要大于等于56,就意味着无法同时写下8+64位,结束的情况一定是写下oriSize
{
memcpy(buf+offset, str + counter, cpyLen);//先行拷贝
offset += cpyLen;
size -= cpyLen;
counter += cpyLen;
if (offset == 64)
{
Process();
continue;
}
buf[offset] = 128;//0x10000000
memset(buf + offset + 1, 0, 64 - offset - 1);//剩余全部填充0
needAddEnd = false;
Process();
}
else
{
if (needAddEnd) {
memcpy(buf+offset, str + counter, size);//拷贝剩余字节
offset += size;
buf[offset] = 128;//0x10000000
memset(buf + offset + 1, 0, 64 - offset - 1);//剩余全部填充0
}
else
{
memset(buf+offset, 0, 64-offset);//在前一项已经填充过0,证明一定填充过0x10000000,所以这就只用填充0
}
uchar* ucSize = longTouchar(totalLen * (long)8);
//将int复制到buf上最后8个字节上去
memcpy(buf + 56, ucSize, 4);
delete ucSize;
Process();
break;
}
}
else {
if (size >= surplusLen) {
memcpy(buf+offset, str, surplusLen);
Process();
size -= surplusLen;
}
else {
memcpy(buf+offset, str, size);
offset += size;
break;
}
}
}
}
md5::md5(uint totalLen)
{
virtualVals[0] = A;
virtualVals[1] = B;
virtualVals[2] = C;
virtualVals[3] = D;
buf = 0;
this->totalLen = totalLen;
}
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;
}
调用
const char* data1 = "E10ADC3949BA59ABBE56E057F20F883E";
const char* data2 = "E10ADC3949BA59ABBE56E057F20F883E";
const char* data3 = "E10ADC3949BA59ABBE56E057F20F883E";
const char* data4 = "E10ADC3949BA59ABBE56E057F20F883E";
md5 m5(128);
m5.update((uchar*)data1, strlen(data1), false);
m5.update((uchar*)data2, strlen(data2), false);
m5.update((uchar*)data3, strlen(data3), false);
m5.update((uchar*)data4, strlen(data4), true);
uchar* pmd5 = m5.getResult();
std::string md5ret = getHexStr(pmd5, 16);
cout << md5ret.c_str() << endl;
2023.3.21 优化分段更新