1. 程式人生 > 實用技巧 >md5演算法 C++ 實現

md5演算法 C++ 實現

#include <iostream>
#include <string>
#include <cmath>
#include <fstream>
using namespace std;

typedef unsigned char byte;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef uint (*func) (uint, uint, uint);


 class Md5 {
 public:
 	// 加密字串
 	string encryption(string s){
 		return encryption((byte *)s.c_str(), s.size());
 	}

 	// 加密byte
 	string encryption(byte *text, uint len){
 		init();
 		encryption_byte(text, len);
 		encryption_last();
 		return byte_to_hex_string(result, 16);
 	}

 	// 加密檔案
 	string encryption_file(string file_name){
 		ifstream fin(file_name);
 		char buf[1024];
 		init();
 		while(!fin.eof()){
 			fin.read(buf, 1024);
 			streamsize len = fin.gcount();
 			if(len)  encryption_byte((byte *)buf, len);
 		}
 		encryption_last();
 		fin.close();
 		return byte_to_hex_string(result, 16);
 	}

 private:
 	inline void init(){
 		memcpy(chunk, CHUNK, sizeof CHUNK);
 		length = 0ULL;
 	}

 	static inline uint F(uint x, uint y, uint z){
 		return x & y | ~x & z;
 	}

 	static inline uint G(uint x, uint y, uint z){
 		return x & z | ~z & y;
 	}

 	static inline uint H(uint x, uint y, uint z){
 		return x ^ y ^ z;
 	}

 	static inline uint I(uint x, uint y, uint z){
 		return y ^ (~z | x);
 	}

 	static inline uint left_shit(uint num, uint bits){
 		return num << bits | num >> 32 - bits;
 	}

 	static inline void convert(uint (*f)(uint, uint, uint), uint &a, uint &b, uint &c, uint &d, uint m, uint t, uint s){
 		a = b + left_shit(a + f(b, c, d) + m + t, s);
 	}

 	static inline void byte_to_uint(const byte *src, uint *dst, uint len){
 		for(uint i = 0, j = 0; i < len; i += 4)
 			dst[j++] = src[i] | (uint)src[i+1] << 8 | (uint)src[i+2] << 16 | (uint)src[i+3] << 24;
 	}

 	static inline void uint_to_byte(uint *src, byte *dst, uint len){
 		for(uint i = 0, j = 0; i < len; ++i)
 			for (int k = 0; k < 30; k += 8)
 				dst[j++] = src[i] >> k & 0xff;
 	}

 	static inline void ull_to_byte(ull src, byte *dst){
 		for(uint i = 0; i < 60; i += 8)
 			dst[i>>3] = src >> i & 0xff;
 	}

 	static inline char byte_to_hex(uint c){
 		if(c <= 9)  return c + '0';
 		return c - 10 + 'A';
 	}

 	static inline string byte_to_hex_string(byte *s, uint len){
 		string res = "";
 		for(uint i = 0; i < len; ++i){
 			res.push_back(byte_to_hex(s[i]>>4));
 			res.push_back(byte_to_hex(s[i]&0x0f));
 		}
 		return res;
 	}


 	// 把data進行加密的過程,每次只能加密512bits
 	void md5_process(const byte* data){
 		uint a[4];
 		memcpy(a, chunk, sizeof chunk);
 		uint m[16];
 		uint sin_count = 0;
 		byte_to_uint(data, m, 64);

 		// 64次轉換
 		for(int i = 0; i < 4; ++i)
 			for(int j = 16; j; --j)
 				convert(A_F[i], a[j&0x03], a[j+1&0x03], a[j+2&0x03], a[j+3&0x03], m[M_INDEX[i][16-j]], (0x100000000UL)*abs(sin(++sin_count)), S[i][16-j&0x03]);
 		
 		// 更新chunk
 		for(int i = 0; i < 4; ++i)
 			chunk[i] += a[i];
 	}

 	// 在前面的基礎上加密data資料,
 	void encryption_byte(const byte *data, uint len){
 		// 計算多餘長度
 		uint index = length >> 3 & 0x3f;
 		length += len << 3;
 		// 計算在buffer中的位置
 		uint det = 64 - index;
 		uint i = 0;
 		// 把data進行切片,然後進行md5加密
 		if(len >= det){
 			memcpy(buffer + index, data, det);
 			md5_process(buffer);
 			i = det;
 			while(i + 63 < len){
 				md5_process(data + i);
 				i += 64;
 			}
 			index = 0;
 		}
 		// data剩餘的資料
 		memcpy(buffer + index, data + i, len - i);
 	}

 	void encryption_last(){
 		byte length_buffer[8];
 		// 獲取長度的byte
 		ull_to_byte(length, length_buffer);
 		uint index = length >> 3 & 0x3f;
 		// 填充字元
 		encryption_byte(FILL_DATA, index < 56 ? 56 - index : 120 - index);
 		encryption_byte(length_buffer, 8);
 		// 轉成16進位制
 		uint_to_byte(chunk, result, 16);
 	}



private:
	static const uint CHUNK[4];
	static const uint S[4][4];
	static const func A_F[4];
	static const byte FILL_DATA[64];
	static const uint M_INDEX[4][16];
	uint chunk[4];
	byte result[16];
	byte buffer[64];
	ull length;
 };

 const uint Md5::CHUNK[4] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
 const uint Md5::S[4][4] = {
		{7, 12, 17, 22},
		{5, 9, 14, 20},
		{4, 11, 16, 23},
		{6, 10, 15, 21}
	};
const byte Md5::FILL_DATA[64] = {0x80};
const func Md5::A_F[4] = {F, G, H, I};
const uint Md5::M_INDEX[4][16] = {
 		{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
 		{ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 },
 		{ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 },
 		{ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }
 	};