void util::md5(std::string& out, const void* data, int len, int end) {
// https://zh.wikipedia.org/zh-sg/MD5
struct helper {
unsigned char data[64];
unsigned long long count;
unsigned int h[4];
void init() {
h[0] = 0x67452301;
h[1] = 0xEFCDAB89;
h[2] = 0x98BADCFE;
h[3] = 0x10325476;
}
void little_endian(unsigned char* output, unsigned int* input, unsigned int len) {
for (unsigned int i = 0, j = 0; i < len; i++, j += 4) {
output[j] = input[i] & 0xFF;
output[j + 1] = (input[i] >> 8) & 0xFF;
output[j + 2] = (input[i] >> 16) & 0xFF;
output[j + 3] = (input[i] >> 24) & 0xFF;
}
}
void compute() {
// clang-format off
static const unsigned int r[] = {
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,
};
static const unsigned int k[] = { // for i from 0 to 63 -> k[i] = floor(abs(sin(i + 1)) * (2^32))
3614090360,3905402710,606105819,3250441966,4118548399,1200080426,2821735955,4249261313,1770035416,2336552879,4294925233,2304563134,1804603682,4254626195,2792965006,1236535329,
4129170786,3225465664,643717713,3921069994,3593408605,38016083,3634488961,3889429448,568446438,3275163606,4107603335,1163531501,2850285829,4243563512,1735328473,2368359562,
4294588738,2272392833,1839030562,4259657740,2763975236,1272893353,4139469664,3200236656,681279174,3936430074,3572445317,76029189,3654602809,3873151461,530742520,3299628645,
4096336452,1126891415,2878612391,4237533241,1700485571,2399980690,4293915773,2240044497,1873313359,4264355552,2734768916,1309151649,4149444226,3174756917,718787259,3951481745,
};
// clang-format on
unsigned int w[16] = {0};
for (unsigned int i = 0, j = 0; j < 64; i++, j += 4) {
w[i] = (this->data[j]) | (this->data[j + 1] << 8) | (this->data[j + 2] << 16) | (this->data[j + 3] << 24);
}
unsigned int a = this->h[0], b = this->h[1], c = this->h[2], d = this->h[3];
for (unsigned int i = 0; i < 64; i++) {
unsigned int f = 0, g = 0, x = 0;
if (0 <= i and i < 16) {
f = (b & c) | ((~b) & d);
g = i;
} else if (16 <= i and i < 32) {
f = (d & b) | ((~d) & c);
g = (5 * i + 1) % 16;
} else if (32 <= i and i < 48) {
f = b ^ c ^ d;
g = (3 * i + 5) % 16;
} else {
f = c ^ (b | (~d));
g = (7 * i) % 16;
}
unsigned int temp = d;
d = c;
c = b;
x = a + f + k[i] + w[g];
b = ((x << r[i]) | (x >> (32 - r[i]))) + b;
a = temp;
}
this->h[0] += a;
this->h[1] += b;
this->h[2] += c;
this->h[3] += d;
}
void finish(std::string& out) {
int left = this->count % 64;
if (left < 56) {
this->data[left] = 1 << 7;
for (int i = left + 1; i < 56; i++) {
this->data[i] = 0;
}
}
unsigned char count_bits[8];
unsigned long long bit_length = this->count * 8;
this->little_endian(count_bits, (unsigned int*)&bit_length, 2);
memcpy(this->data + 56, count_bits, 8);
this->compute();
unsigned char decrypt[16];
this->little_endian(decrypt, this->h, 4);
char result[33] = {0};
for (int i = 0; i < 16; i++) {
sprintf(result + i * 2, "%02x", decrypt[i]);
}
out = result;
}
};
if (out.length() == 0) {
out.resize(sizeof(helper));
((helper*)out.data())->init();
}
helper* p = (helper*)out.data();
int offset = 0;
while (offset < len) {
int append = 64 - p->count % 64;
if (append > len - offset) {
append = len - offset;
}
memcpy(p->data + (p->count % 64), ((unsigned char*)data) + offset, append);
offset += append;
p->count += append;
if (p->count % 64 == 0) {
p->compute();
}
}
if (end) {
p->finish(out);
}
}
使用
std::string out;
util::md5(out, "hello", 5, true);
分步添加
std::string out;
util::md5(out, "hello", 5, false);
util::md5(out, "world", 5, true);