md5算法
创建:2023-10-27 16:47
更新:2023-10-27 17:07
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);