放一波代码吧,MD5已经不是检查数据完整性的最佳选择了QAQ(但是有一定的教学意义)
基本原理网上都有,这份代码核心部分(压缩函数)也是从cryptopp搞来的,其他的填充啥的自己写的。就…称我为缝合怪吧hhh
注:由于填充过程是对整个数据读进内存然后进行的填充,所以计算大文件Hash时悠着点啊,内存炸了别赖我
md5.h
#ifndef MD5_H
#define MD5_H
#include<iostream>
using namespace std;
typedef unsigned int uint32;
typedef unsigned char uint8;
typedef unsigned long long uint64;
#define F(b, c, d) ((b & c) | ((~b) & d))
#define G(b, c, d) ((b & d) | (c & (~d)))
#define H(b, c, d) (b ^ c ^ d)
#define I(b, c, d) (c ^ (b | ~d))
#define CLS(x, s) ((x << s)|(x >> (32 - s)))
#define ROUND(f, w, x, y, z, data, s) \
w = CLS(w + f(x, y, z) + data, s) + x
class MD5 {
private:
// 4 32-bit registers
uint32 ctx[4] = { 0x67452301L,0xefcdab89L,0x98badcfeL,0x10325476L };
uint32* wordptr = NULL;
uint8* byteptr = NULL;
uint32 count = 0;
// computer's endianess(little->false, big->true)
bool endian = true;;
public:
MD5() {
// test computer's endianess
uint32 a = 0x01;
uint8* b = (uint8*)&a;
// set 'endian' flag
if (*b == 0x01) {
endian = false;
}
else if (*b == 0x00) {
endian = true;
}
}
void Load(uint8* data, uint64 len);
void Transform();
string GetMD5Hash(uint8* data, uint64 size);
string GetFileMD5Hash(string filename);
};
#endif
md5.cpp
#include<iostream>
#include<fstream>
#include<math.h>
#include<windows.h>
#include"md5.h"
#include"utils.h"
void MD5::Load(uint8* data, uint64 size) {
// get the length of data after padding
uint64 bytelen = (size & 0x3f) < 56 ? (64 - (size & 0x3f) + size) : (64 - (size & 0x3f) + size + 64);
// get the number of 512-bit blocks
count = ceil((double)bytelen / 64);
// create a new array
wordptr = (uint32*)malloc(bytelen);
if (wordptr != NULL) {
byteptr = (uint8*)wordptr;
// set zeros
memset(wordptr, 0x00, bytelen);
// copy 'data' to 'wordptr'/'byteptr'
memcpy(byteptr, data, size);
// add 0x80
*(byteptr + size) = 0x80;
// add data's length
if (endian == true) {
// big-endian
*(uint64*)(wordptr + bytelen / 4 - 2) = EndianTransfrom(size << 3);
}
else {
// little-endian
*(uint64*)(wordptr + bytelen / 4 - 2) = size << 3;
}
}
return;
}
void MD5::Transform() {
uint32 tmp, a, b, c, d;
for (register int i = 0; i < count; i++) {
int offset = i << 4;
a = ctx[0]; b = ctx[1]; c = ctx[2]; d = ctx[3];
ROUND(F, a, b, c, d, wordptr[offset + 0] + 0xd76aa478, 7);
ROUND(F, d, a, b, c, wordptr[offset + 1] + 0xe8c7b756, 12);
ROUND(F, c, d, a, b, wordptr[offset + 2] + 0x242070db, 17);
ROUND(F, b, c, d, a, wordptr[offset + 3] + 0xc1bdceee, 22);
ROUND(F, a, b, c, d, wordptr[offset + 4] + 0xf57c0faf, 7);
ROUND(F, d, a, b, c, wordptr[offset + 5] + 0x4787c62a, 12);
ROUND(F, c, d, a, b, wordptr[offset + 6] + 0xa8304613, 17);
ROUND(F, b, c, d, a, wordptr[offset + 7] + 0xfd469501, 22);
ROUND(F, a, b, c, d, wordptr[offset + 8] + 0x698098d8, 7);
ROUND(F, d, a, b, c, wordptr[offset + 9] + 0x8b44f7af, 12);
ROUND(F, c, d, a, b, wordptr[offset + 10] + 0xffff5bb1, 17);
ROUND(F, b, c, d, a, wordptr[offset + 11] + 0x895cd7be, 22);
ROUND(F, a, b, c, d, wordptr[offset + 12] + 0x6b901122, 7);
ROUND(F, d, a, b, c, wordptr[offset + 13] + 0xfd987193, 12);
ROUND(F, c, d, a, b, wordptr[offset + 14] + 0xa679438e, 17);
ROUND(F, b, c, d, a, wordptr[offset + 15] + 0x49b40821, 22);
ROUND(G, a, b, c, d, wordptr[offset + 1] + 0xf61e2562, 5);
ROUND(G, d, a, b, c, wordptr[offset + 6] + 0xc040b340, 9);
ROUND(G, c, d, a, b, wordptr[offset + 11] + 0x265e5a51, 14);
ROUND(G, b, c, d, a, wordptr[offset + 0] + 0xe9b6c7aa, 20);
ROUND(G, a, b, c, d, wordptr[offset + 5] + 0xd62f105d, 5);
ROUND(G, d, a, b, c, wordptr[offset + 10] + 0x02441453, 9);
ROUND(G, c, d, a, b, wordptr[offset + 15] + 0xd8a1e681, 14);
ROUND(G, b, c, d, a, wordptr[offset + 4] + 0xe7d3fbc8, 20);
ROUND(G, a, b, c, d, wordptr[offset + 9] + 0x21e1cde6, 5);
ROUND(G, d, a, b, c, wordptr[offset + 14] + 0xc33707d6, 9);
ROUND(G, c, d, a, b, wordptr[offset + 3] + 0xf4d50d87, 14);
ROUND(G, b, c, d, a, wordptr[offset + 8] + 0x455a14ed, 20);
ROUND(G, a, b, c, d, wordptr[offset + 13] + 0xa9e3e905, 5);
ROUND(G, d, a, b, c, wordptr[offset + 2] + 0xfcefa3f8, 9);
ROUND(G, c, d, a, b, wordptr[offset + 7] + 0x676f02d9, 14);
ROUND(G, b, c, d, a, wordptr[offset + 12] + 0x8d2a4c8a, 20);
ROUND(H, a, b, c, d, wordptr[offset + 5] + 0xfffa3942, 4);
ROUND(H, d, a, b, c, wordptr[offset + 8] + 0x8771f681, 11);
ROUND(H, c, d, a, b, wordptr[offset + 11] + 0x6d9d6122, 16);
ROUND(H, b, c, d, a, wordptr[offset + 14] + 0xfde5380c, 23);
ROUND(H, a, b, c, d, wordptr[offset + 1] + 0xa4beea44, 4);
ROUND(H, d, a, b, c, wordptr[offset + 4] + 0x4bdecfa9, 11);
ROUND(H, c, d, a, b, wordptr[offset + 7] + 0xf6bb4b60, 16);
ROUND(H, b, c, d, a, wordptr[offset + 10] + 0xbebfbc70, 23);
ROUND(H, a, b, c, d, wordptr[offset + 13] + 0x289b7ec6, 4);
ROUND(H, d, a, b, c, wordptr[offset + 0] + 0xeaa127fa, 11);
ROUND(H, c, d, a, b, wordptr[offset + 3] + 0xd4ef3085, 16);
ROUND(H, b, c, d, a, wordptr[offset + 6] + 0x04881d05, 23);
ROUND(H, a, b, c, d, wordptr[offset + 9] + 0xd9d4d039, 4);
ROUND(H, d, a, b, c, wordptr[offset + 12] + 0xe6db99e5, 11);
ROUND(H, c, d, a, b, wordptr[offset + 15] + 0x1fa27cf8, 16);
ROUND(H, b, c, d, a, wordptr[offset + 2] + 0xc4ac5665, 23);
ROUND(I, a, b, c, d, wordptr[offset + 0] + 0xf4292244, 6);
ROUND(I, d, a, b, c, wordptr[offset + 7] + 0x432aff97, 10);
ROUND(I, c, d, a, b, wordptr[offset + 14] + 0xab9423a7, 15);
ROUND(I, b, c, d, a, wordptr[offset + 5] + 0xfc93a039, 21);
ROUND(I, a, b, c, d, wordptr[offset + 12] + 0x655b59c3, 6);
ROUND(I, d, a, b, c, wordptr[offset + 3] + 0x8f0ccc92, 10);
ROUND(I, c, d, a, b, wordptr[offset + 10] + 0xffeff47d, 15);
ROUND(I, b, c, d, a, wordptr[offset + 1] + 0x85845dd1, 21);
ROUND(I, a, b, c, d, wordptr[offset + 8] + 0x6fa87e4f, 6);
ROUND(I, d, a, b, c, wordptr[offset + 15] + 0xfe2ce6e0, 10);
ROUND(I, c, d, a, b, wordptr[offset + 6] + 0xa3014314, 15);
ROUND(I, b, c, d, a, wordptr[offset + 13] + 0x4e0811a1, 21);
ROUND(I, a, b, c, d, wordptr[offset + 4] + 0xf7537e82, 6);
ROUND(I, d, a, b, c, wordptr[offset + 11] + 0xbd3af235, 10);
ROUND(I, c, d, a, b, wordptr[offset + 2] + 0x2ad7d2bb, 15);
ROUND(I, b, c, d, a, wordptr[offset + 9] + 0xeb86d391, 21);
ctx[0] += a; ctx[1] += b; ctx[2] += c; ctx[3] += d;
}
}
string MD5::GetMD5Hash(uint8* data, uint64 size) {
Load(data, size);
Transform();
free(byteptr);
return bytesToHexString((uint8*)ctx, 16);
}
string MD5::GetFileMD5Hash(string filename) {
// get file's size
ifstream fin(filename, ios::in | ios::binary);
fin.seekg(0, ios::end);
uint64 size = fin.tellg();
fin.seekg(0, ios::beg);
// initialize timer's variables
LARGE_INTEGER cpuFreq, startTime, endTime;
double runtime;
QueryPerformanceFrequency(&cpuFreq);
QueryPerformanceCounter(&startTime);
// read data
uint8* data = (uint8*)malloc(size);
memset(data, 0, size);
fin.read((char*)data, size);
fin.close();
// compute hash and test md5's speed
QueryPerformanceCounter(&startTime);
string result = GetMD5Hash(data, size);
QueryPerformanceCounter(&endTime);
runtime = (((endTime.QuadPart - startTime.QuadPart) * 1.0f) / cpuFreq.QuadPart);
printf("MD5 Speed: %lf MB/s\n", size * 1.0 / runtime / 1024 / 1024);
free(data);
return result;
}