#ifndef YMD5_H_
#define YMD5_H_
#include <string>
using std::string;
namespace yyy {
typedef unsigned int uint32;
class MD5 {
public:
static string Md5(const string& s);
static char* Md5(char* r, const char* s);
private:
//对数组做填充
static size_t AppendString(char* buf, size_t textlen);
//四轮处理
static void FourRoundRun(uint32 res[], const char* buf);
//数组中的每个gn[i][j]元素通过公式: 2 * sin(16* 1) 32 i + j + 计算后取整得到
static uint32 gn[4][16];
//做循环移位的步数
static int move[4][16];
};
}
#endif
#include "YMd5.h"
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
namespace yyy {
//四个逻辑函数,用函数指针数组组织
static inline uint32 F(uint32 x, uint32 y, uint32 z) { return (x&y)|((~x)&z);}
static inline uint32 G(uint32 x, uint32 y, uint32 z) { return (x&z)|(y&(~z));}
static inline uint32 H(uint32 x, uint32 y, uint32 z) { return x^y^z;}
static inline uint32 I(uint32 x, uint32 y, uint32 z) { return y^(x|(~z));}
typedef uint32 (*P_FUN)(uint32 x, uint32 y, uint32 z);
P_FUN pfun[4] = {F, G, H, I};
//将整数x循环左移n位
static inline uint32 CirLeftMove(uint32 x, int n) { return (x<<n)|((x&0xffffffff)>>(32-n)); }
//将buf从start开始的offset个字节内存赋值到a这个uint数组,要求a的长度是offset/4(向上取整)
static inline void Char2Uint(uint32 a[], const char* buf, const int len) { memcpy(a, buf, len); }
//将a从start开始的offset个整数内存赋值到buf这个字符串,要求buf的长度是4*offset
static inline char* Uint2Char(char* buf, const uint32 a[], const int offset) { memcpy(buf, a, offset*4); }
//将a数组,按16进制输出成字符串数组,输入buf长度大于32+1,函数里面不作检查
static const char int2hex[17] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static inline char* Uint2HexString(char* buf, const uint32 a[], const int len) {
int i = -1;
for (int j = 0; j < len; ++j) {
buf[++i] = int2hex[(a[j] >> 4) & 0xf];
buf[++i] = int2hex[(a[j] >> 0) & 0xf];
buf[++i] = int2hex[(a[j] >> 12) & 0xf];
buf[++i] = int2hex[(a[j] >> 8) & 0xf];
buf[++i] = int2hex[(a[j] >> 20) & 0xf];
buf[++i] = int2hex[(a[j] >> 16) & 0xf];
buf[++i] = int2hex[(a[j] >> 28) & 0xf];
buf[++i] = int2hex[(a[j] >> 24) & 0xf];
}
buf[++i] = 0;
return buf;
}
int MD5::move[4][16] = {
{ 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 }};
uint32 MD5::gn[4][16] = {
{ 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 }};
#define J_TO_I(i, j) {\
if (r == 0) i = j & 0xf; \
else if (r == 1) i = (1+5*j) & 0xf; \
else if (r == 2) i = (5+3*j) & 0xf; \
else if (r == 3) i = (7*j) & 0xf; \
}
inline void MD5::FourRoundRun(uint32 res[], const char * buf) {
uint32 a[16];
Char2Uint(a, buf, 64);
uint32 tmp_res[4];
memcpy(tmp_res, res, sizeof(res)*4);
for(int r = 0; r < 4; ++r) {
for (int j = 0; j < 16; ++j) {
int i = 0;
J_TO_I(i, j);
tmp_res[0] = tmp_res[1] + CirLeftMove(tmp_res[0] + (*(pfun[r]))(tmp_res[1], tmp_res[2], tmp_res[3]) + a[i] + gn[r][j], move[r][j]);
int tmp = tmp_res[3];
tmp_res[3] = tmp_res[2];
tmp_res[2] = tmp_res[1];
tmp_res[1] = tmp_res[0];
tmp_res[0] = tmp;
}
}
res[0] += tmp_res[0];
res[1] += tmp_res[1];
res[2] += tmp_res[2];
res[3] += tmp_res[3];
}
char* MD5::Md5(char* r, const char* s) {
uint32 temp[4], result[4] = { 0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476 };
const size_t BUFLEN = 64;
char buf[BUFLEN*2+1];
size_t offset = 0, len = 0;
memcpy(temp, result, sizeof(result));
bool end = false;
while (!end) {
strncpy(buf, s+offset, BUFLEN);
buf[BUFLEN] = 0;
len = strlen(buf);
offset += len;
if (len < BUFLEN) {
len = AppendString(buf, strlen(s));
end = true;
}
if (len == 64) {
FourRoundRun(result, buf);
} else if (len == 128) {
FourRoundRun(result, buf);
FourRoundRun(result, buf+BUFLEN);
}
}
strcpy(r, Uint2HexString(buf, result, 4));
return r;
}
string MD5::Md5(const string& s) {
char res[33];
Md5(res, s.c_str());
return string(res);
}
inline size_t MD5::AppendString(char* buf, size_t textlen) { //这里必须保证使用的buf有(64*2+1)byte的长度
size_t append_len, retlen, len = strlen(buf);
size_t res = len&0x3f;
if (res >= 56) {
append_len = 64 - res + 56;
retlen = 128;
} else if (res < 56) {
append_len = 56 - res;
retlen = 64;
}
*(buf+len) = 0x80;
memset(buf+len+1, 0, append_len-1);
textlen *= 8;//转换成bit长度
memcpy(buf+len+append_len, &textlen, sizeof(size_t));
return retlen;
}
}