# MD5算法

C++11 code, Linux。 本人测试PC小端字节序

## 代码片段(4)[全屏查看所有代码]

### 1. [代码]main.cpp     跳至 [1] [2] [3] [全屏预览]

```#include "MD5.h"
#include <cstdio>

MD5::Result hash(const char *data, size_t len, MD5& algo)
{
MD5::Result res;
algo.reset();
algo.finish(res);
return res;
}

void hexhash(const MD5::Result& res)
{
for (size_t i=0; i<res.size(); ++i)
printf("%02x", res[i]);
printf("\n");
}

int main(void)
{
MD5 algo;

hexhash(hash("",    0, algo));
hexhash(hash("123", 3, algo));
hexhash(hash("abc", 3, algo));

return 0;
}```

### 2. [代码]MD5.h     跳至 [1] [2] [3] [全屏预览]

```// -*-Mode: C++;-*-
#ifndef QQ371432590_MD5_H_
#define QQ371432590_MD5_H_

#include <cstdint> // uintX_t
#include <cstddef> // size_t
#include <array>

class MD5
{
public:
typedef char                    byte_type;
typedef byte_type               Byte;
typedef std::array<uint8_t, 16> result_type;
typedef result_type             Result;

void reset();
void add(const Byte* d, size_t n);
void finish(result_type& res);
private:
uint64_t count_;
uint8_t buffer_[64];
uint32_t state_[4];
};

#endif // QQ371432590_MD5_H_
```

### 3. [代码]MD5.cpp     跳至 [1] [2] [3] [全屏预览]

```#include "MD5.h"
#include <endian.h> // freeBSD <sys/endian.h>
#include <cstring> // memset  memcpy

namespace {
typedef uint32_t U32;
typedef uint64_t U64;

inline U32& encode(U32& x) {return x = htole32(x);}
inline void encode(U64& x) {x = htole64(x);}
inline void decode(U32& x) {x = htole32(x);}

void MD5_transform(U32* state_, U32* x);
} // Private namespace.

void MD5::reset()
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
enum Encode : U32 {
state_0 = 0x67452301, state_1 = 0xefcdab89,
state_2 = 0x98badcfe, state_3 = 0x10325476
};
#else
enum Encode : U32 {
state_0 = 0x01234567, state_1 = 0x89abcdef,
state_2 = 0xfedcba98, state_3 = 0x76543210
};
#endif
count_    = 0;
state_[0] = Encode::state_0;
state_[1] = Encode::state_1;
state_[2] = Encode::state_2;
state_[3] = Encode::state_3;
std::memset(buffer_, 0, sizeof(buffer_));
}

void MD5::add(const Byte* cd, size_t sz)
{
//assert(sz < (sz<<3));
//assert(sz<<3 <= UINT64_MAX-count_);

size_t startPos = static_cast<size_t>((count_ >> 3) & 63);
size_t partSize = sizeof(buffer_) - startPos;
count_ += static_cast<uint64_t>(sz << 3);

if (sz >= partSize) {
std::memcpy(&buffer_[startPos], cd, partSize);
MD5_transform(state_, reinterpret_cast<U32*>(buffer_));
sz -= partSize;
cd += partSize;
startPos = 0;
while (sz >= sizeof(buffer_)) {
std::memcpy(buffer_, cd, sizeof(buffer_));
MD5_transform(state_, reinterpret_cast<U32*>(buffer_));
sz -= sizeof(buffer_);
cd += sizeof(buffer_);
}
}

std::memcpy(&buffer_[startPos], cd, sz);
}

void MD5::finish(result_type& res)
{
size_t startPos = static_cast<size_t>((count_>>3) & 0x3f);
buffer_[startPos++] = 0x80;
size_t partSize = sizeof(buffer_) - startPos;

if (partSize < 8) {
std::memset(&buffer_[startPos], 0, partSize);
MD5_transform(state_, reinterpret_cast<U32*>(buffer_));
std::memset(buffer_, 0, sizeof(buffer_)-8);
} else /* if (partSize >= 8) */ {
std::memset(&buffer_[startPos], 0, partSize-8);
}

{
auto p = reinterpret_cast<U64*>(&buffer_[sizeof(buffer_)-8]);
*p = count_;
encode(*p);
}
MD5_transform(state_, reinterpret_cast<U32*>(buffer_));

decode(state_[0]);
decode(state_[1]);
decode(state_[2]);
decode(state_[3]);
std::memcpy(res.data(), state_, res.size());
}

namespace {
#define F1(x,y,z) (z^(x&(y^z)))
#define F2(x,y,z) F1(z,x,y)
#define F3(x,y,z) (x^y^z)
#define F4(x,y,z) (y^(x|~z))
#define ROL(x,n) ((x<<n)|(x>>(32-n)))
#define ROUND(f,a,b,c,d,x,n) (a+=(f(b,c,d)+x), a=ROL(a,n), a+=b)

void MD5_transform(U32* state_, U32* x)
{
U32 a = state_[0];
U32 b = state_[1];
U32 c = state_[2];
U32 d = state_[3];

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

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

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

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

state_[0] += a;
state_[1] += b;
state_[2] += c;
state_[3] += d;
} // MD5_transform

} // Private namespace.
```