一、概述

哈希算法的概念最早可以追溯到20世纪50年代,用于高效数据存储和检索。1953年,汉斯·彼得·卢恩(Hans Peter Luhn)提出了一种基于关键字的散列方法,用于快速访问信息。随后,哈希表(Hash Table)的设计逐渐成熟,成为计算机科学中基础数据结构之一。加密哈希函数的发展与密码学需求紧密相关,例如MD5(1991年)和SHA家族(1993年至今)的诞生,均是为了解决数据完整性验证和安全性问题。

之所以用来校验数据、防篡改,主要因为它的以下几个特性:

  1. 确定性,相同的输入永远不会产生不同的输出。假设有一个文件A,它的SHA256值(当然也可以是其他算法)是X,如果A没有被修改,那么它的SHA256就一定是X,永远不会改变。
  2. 唯一性(几乎),两组不同的数据基本不可能产生相同的哈希值。但这并不代表哈希值没有重复的可能性,因为数据的组合数量肯定要比哈希字符串多得多。(例子放在文章最后)
  3. 不可逆性,将哈希值还原成原始数据几乎是不可能的。
  4. 长度确定性。这使得它可以在密码学中起到很大作用,比如AES-256的密钥必须是32字节,但如果想要使用不同长度的密码(或密钥),就可以先计算输入密钥的SHA-256,再将二进制SHA-256数据作为二次密钥应用于AES-256加密,而且足够安全。

但哈希算法相对复杂,C++中通常需要依赖openssl这样的库才能实现。那么今天,作者就实现了常用的哈希算法,可以直接include在代码里使用。

废话不多说,上代码!

二、代码实现

1. 算法实现

本文的所有代码需要在C++14标准下编译(MinGW 4.9+或VS2013+ / Dev-C++ 5.11+),不然可能报错!

哈希算法原理十分复杂,这里不再多说。下面的代码可以直接放在一个.hpp里,include使用,方法和Python的hashlib相同。(作者原创代码,转载请声明出处!

/*
MD5及SHA家族哈希算法实现
(c) Copyright 2025
By 金煜力,2025-7-19 ~ 2025-8-31
*/

#pragma once

#include <string>
#include <vector>
#include <cstdint>
#include <array>
#include <stdexcept>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <cstring>

// ================= MD5 =================
constexpr uint32_t MD5_S[64] = {
    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
};
constexpr uint32_t MD5_K[64] = {
    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
};
inline uint32_t md5_left_rotate(uint32_t x, uint32_t n) {
    return (x << n) | (x >> (32 - n));
}
inline uint32_t md5_to_little_endian(const uint8_t* bytes) {
    return static_cast<uint32_t>(bytes[0])
        | (static_cast<uint32_t>(bytes[1]) << 8)
        | (static_cast<uint32_t>(bytes[2]) << 16)
        | (static_cast<uint32_t>(bytes[3]) << 24);
}
class MD5 {
public:
    MD5() : A(0x67452301), B(0xefcdab89), C(0x98badcfe), D(0x10325476), total_bytes(0), finished(false) {
        buffer.reserve(64);
        digest_result.fill(0);
    }
    void update(const void* data, size_t length) {
        if (finished) return;
        const uint8_t* ptr = static_cast<const uint8_t*>(data);
        total_bytes += length;
        if (!buffer.empty()) {
            size_t to_copy = std::min<size_t>(64 - buffer.size(), length);
            buffer.insert(buffer.end(), ptr, ptr + to_copy);
            ptr += to_copy;
            length -= to_copy;
            if (buffer.size() == 64) {
                transform(buffer.data());
                buffer.clear();
            }
        }
        while (length >= 64) {
            transform(ptr);
            ptr += 64;
            length -= 64;
        }
        if (length > 0) {
            buffer.insert(buffer.end(), ptr, ptr + length);
        }
    }
    void update(const std::string& data) { update(data.data(), data.size()); }
    void update(const std::vector<uint8_t>& data) { update(data.data(), data.size()); }
    void finalize() {
        if (!finished) do_finalize();
    }
    std::string digest() {
        if (!finished) do_finalize();
        return std::string(digest_result.begin(), digest_result.end());
    }
    std::string hexdigest() {
        if (!finished) do_finalize();
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (uint8_t c : digest_result) {
            oss << std::setw(2) << static_cast<unsigned>(c);
        }
        return oss.str();
    }
private:
    uint32_t A, B, C, D;
    uint64_t total_bytes;
    std::vector<uint8_t> buffer;
    bool finished;
    std::array<uint8_t, 16> digest_result;
    void transform(const uint8_t* block) {
        uint32_t a = A, b = B, c = C, d = D;
        uint32_t X[16];
        for (int i = 0; i < 16; ++i) {
            X[i] = md5_to_little_endian(block + i * 4);
        }
        for (int i = 0; i < 64; ++i) {
            uint32_t F, g;
            if (i < 16) {
                F = (b & c) | ((~b) & d);
                g = i;
            } else if (i < 32) {
                F = (d & b) | ((~d) & c);
                g = (5 * i + 1) % 16;
            } else if (i < 48) {
                F = b ^ c ^ d;
                g = (3 * i + 5) % 16;
            } else {
                F = c ^ (b | (~d));
                g = (7 * i) % 16;
            }
            F = F + a + MD5_K[i] + X[g];
            a = d;
            d = c;
            c = b;
            b = b + md5_left_rotate(F, MD5_S[i]);
        }
        A += a;
        B += b;
        C += c;
        D += d;
    }
    void do_finalize() {
        if (finished) return;
        uint64_t bit_length = total_bytes * 8;
        buffer.push_back(0x80);
        size_t orig_size = buffer.size();
        size_t pad_size = (orig_size % 64 < 56) ? (56 - orig_size % 64) : (120 - orig_size % 64);
        buffer.insert(buffer.end(), pad_size, 0);
        for (int i = 0; i < 8; i++) {
            buffer.push_back(static_cast<uint8_t>(bit_length >> (i * 8)));
        }
        for (size_t i = 0; i < buffer.size(); i += 64) {
            transform(buffer.data() + i);
        }
        auto to_le_bytes = [](uint32_t n) -> std::array<uint8_t, 4> {
            return {
                static_cast<uint8_t>(n),
                static_cast<uint8_t>(n >> 8),
                static_cast<uint8_t>(n >> 16),
                static_cast<uint8_t>(n >> 24)
            };
        };
        std::array<uint8_t, 4> a_bytes = to_le_bytes(A);
        std::array<uint8_t, 4> b_bytes = to_le_bytes(B);
        std::array<uint8_t, 4> c_bytes = to_le_bytes(C);
        std::array<uint8_t, 4> d_bytes = to_le_bytes(D);
        std::copy(a_bytes.begin(), a_bytes.end(), digest_result.begin());
        std::copy(b_bytes.begin(), b_bytes.end(), digest_result.begin() + 4);
        std::copy(c_bytes.begin(), c_bytes.end(), digest_result.begin() + 8);
        std::copy(d_bytes.begin(), d_bytes.end(), digest_result.begin() + 12);
        finished = true;
    }
};

// ================= SHA1 =================
class SHA1 {
public:
    SHA1() : h0(0x67452301), h1(0xEFCDAB89), h2(0x98BADCFE), h3(0x10325476), h4(0xC3D2E1F0), total_bytes(0), finished(false) {}
    void update(const void* data, size_t length) {
        if (finished) return;
        const uint8_t* ptr = static_cast<const uint8_t*>(data);
        total_bytes += length;
        if (!buffer.empty()) {
            size_t to_copy = std::min<size_t>(64 - buffer.size(), length);
            buffer.insert(buffer.end(), ptr, ptr + to_copy);
            ptr += to_copy;
            length -= to_copy;
            if (buffer.size() == 64) {
                transform(buffer.data());
                buffer.clear();
            }
        }
        while (length >= 64) {
            transform(ptr);
            ptr += 64;
            length -= 64;
        }
        if (length > 0) {
            buffer.insert(buffer.end(), ptr, ptr + length);
        }
    }
    void update(const std::string& data) { update(data.data(), data.size()); }
    void update(const std::vector<uint8_t>& data) { update(data.data(), data.size()); }
    void finalize() {
        if (!finished) do_finalize();
    }
    std::string digest() {
        if (!finished) do_finalize();
        return std::string(digest_result.begin(), digest_result.end());
    }
    std::string hexdigest() {
        if (!finished) do_finalize();
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (uint8_t c : digest_result) {
            oss << std::setw(2) << static_cast<unsigned>(c);
        }
        return oss.str();
    }
private:
    uint32_t h0, h1, h2, h3, h4;
    uint64_t total_bytes;
    std::vector<uint8_t> buffer;
    bool finished;
    std::array<uint8_t, 20> digest_result;
    void transform(const uint8_t* block) {
        uint32_t w[80];
        for (int i = 0; i < 16; ++i) {
            w[i] = (static_cast<uint32_t>(block[i * 4]) << 24) |
                (static_cast<uint32_t>(block[i * 4 + 1]) << 16) |
                (static_cast<uint32_t>(block[i * 4 + 2]) << 8) |
                static_cast<uint32_t>(block[i * 4 + 3]);
        }
        for (int i = 16; i < 80; ++i) {
            w[i] = left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
        }
        uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
        for (int i = 0; i < 20; ++i) {
            uint32_t f = (b & c) | ((~b) & d);
            uint32_t temp = left_rotate(a, 5) + f + e + 0x5A827999 + w[i];
            e = d; d = c; c = left_rotate(b, 30); b = a; a = temp;
        }
        for (int i = 20; i < 40; ++i) {
            uint32_t f = b ^ c ^ d;
            uint32_t temp = left_rotate(a, 5) + f + e + 0x6ED9EBA1 + w[i];
            e = d; d = c; c = left_rotate(b, 30); b = a; a = temp;
        }
        for (int i = 40; i < 60; ++i) {
            uint32_t f = (b & c) | (b & d) | (c & d);
            uint32_t temp = left_rotate(a, 5) + f + e + 0x8F1BBCDC + w[i];
            e = d; d = c; c = left_rotate(b, 30); b = a; a = temp;
        }
        for (int i = 60; i < 80; ++i) {
            uint32_t f = b ^ c ^ d;
            uint32_t temp = left_rotate(a, 5) + f + e + 0xCA62C1D6 + w[i];
            e = d; d = c; c = left_rotate(b, 30); b = a; a = temp;
        }
        h0 += a; h1 += b; h2 += c; h3 += d; h4 += e;
    }
    void do_finalize() {
        if (finished) return;
        size_t n = buffer.size();
        size_t k = (55 - n + 64) % 64;
        std::vector<uint8_t> padding;
        padding.reserve(n + 1 + k + 8);
        padding = buffer;
        padding.push_back(0x80);
        padding.insert(padding.end(), k, 0);
        uint64_t bit_length = total_bytes * 8;
        for (int i = 0; i < 8; i++) {
            padding.push_back(static_cast<uint8_t>((bit_length >> (56 - i * 8)) & 0xFF));
        }
        for (size_t i = 0; i < padding.size(); i += 64) {
            transform(padding.data() + i);
        }
        auto to_be_bytes = [](uint32_t n, uint8_t* bytes) {
            bytes[0] = static_cast<uint8_t>((n >> 24) & 0xFF);
            bytes[1] = static_cast<uint8_t>((n >> 16) & 0xFF);
            bytes[2] = static_cast<uint8_t>((n >> 8) & 0xFF);
            bytes[3] = static_cast<uint8_t>(n & 0xFF);
        };
        to_be_bytes(h0, digest_result.data());
        to_be_bytes(h1, digest_result.data() + 4);
        to_be_bytes(h2, digest_result.data() + 8);
        to_be_bytes(h3, digest_result.data() + 12);
        to_be_bytes(h4, digest_result.data() + 16);
        finished = true;
    }
    static uint32_t left_rotate(uint32_t x, uint32_t n) {
        return (x << n) | (x >> (32 - n));
    }
};

// ================= SHA256 =================
class SHA256 {
private:
    uint64_t total_bytes;
    std::vector<uint8_t> buffer;
    uint32_t h[8];
    bool finalized;
    static uint32_t rotr(uint32_t x, uint32_t n) {
        return (x >> n) | (x << (32 - n));
    }
    static uint32_t ch(uint32_t x, uint32_t y, uint32_t z) {
        return (x & y) ^ (~x & z);
    }
    static uint32_t maj(uint32_t x, uint32_t y, uint32_t z) {
        return (x & y) ^ (x & z) ^ (y & z);
    }
    static uint32_t sigma0(uint32_t x) {
        return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
    }
    static uint32_t sigma1(uint32_t x) {
        return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
    }
    static uint32_t gamma0(uint32_t x) {
        return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3);
    }
    static uint32_t gamma1(uint32_t x) {
        return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10);
    }
    void process_block(const uint8_t* block) {
        static const std::array<uint32_t, 64> k = {
            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
        };
        std::array<uint32_t, 64> w;
        for (int i = 0; i < 16; ++i) {
            w[i] = (static_cast<uint32_t>(block[i * 4]) << 24) |
                (static_cast<uint32_t>(block[i * 4 + 1]) << 16) |
                (static_cast<uint32_t>(block[i * 4 + 2]) << 8) |
                (static_cast<uint32_t>(block[i * 4 + 3]));
        }
        for (int i = 16; i < 64; ++i) {
            w[i] = gamma1(w[i - 2]) + w[i - 7] + gamma0(w[i - 15]) + w[i - 16];
        }
        uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], h_val = h[7];
        for (int i = 0; i < 64; ++i) {
            uint32_t t1 = h_val + sigma1(e) + ch(e, f, g) + k[i] + w[i];
            uint32_t t2 = sigma0(a) + maj(a, b, c);
            h_val = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
        }
        h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; h[5] += f; h[6] += g; h[7] += h_val;
    }
public:
    SHA256() { reset(); }
    void reset() {
        total_bytes = 0;
        buffer.clear();
        buffer.reserve(64);
        h[0] = 0x6a09e667;
        h[1] = 0xbb67ae85;
        h[2] = 0x3c6ef372;
        h[3] = 0xa54ff53a;
        h[4] = 0x510e527f;
        h[5] = 0x9b05688c;
        h[6] = 0x1f83d9ab;
        h[7] = 0x5be0cd19;
        finalized = false;
    }
    void update(const void* data, size_t len) {
        if (finalized) {
            throw std::runtime_error("SHA256: cannot update after finalization");
        }
        const uint8_t* d = static_cast<const uint8_t*>(data);
        size_t index = 0;
        size_t remaining = len;
        if (!buffer.empty()) {
            size_t buffer_remaining = 64 - buffer.size();
            if (remaining < buffer_remaining) {
                buffer.insert(buffer.end(), d, d + remaining);
                return;
            }
            buffer.insert(buffer.end(), d, d + buffer_remaining);
            process_block(buffer.data());
            total_bytes += 64;
            index += buffer_remaining;
            remaining -= buffer_remaining;
            buffer.clear();
        }
        while (remaining >= 64) {
            process_block(d + index);
            total_bytes += 64;
            index += 64;
            remaining -= 64;
        }
        if (remaining > 0) {
            buffer.insert(buffer.end(), d + index, d + index + remaining);
        }
    }
    void update(const std::string& data) { update(data.data(), data.size()); }
    void update(const std::vector<uint8_t>& data) { update(data.data(), data.size()); }
    void finalize() {
        if (!finalized) do_finalize();
    }
    std::vector<uint8_t> digest() {
        if (!finalized) do_finalize();
        std::vector<uint8_t> result(32);
        for (int i = 0; i < 8; ++i) {
            result[i * 4] = static_cast<uint8_t>(h[i] >> 24);
            result[i * 4 + 1] = static_cast<uint8_t>(h[i] >> 16);
            result[i * 4 + 2] = static_cast<uint8_t>(h[i] >> 8);
            result[i * 4 + 3] = static_cast<uint8_t>(h[i]);
        }
        return result;
    }
    std::string hexdigest() {
        std::vector<uint8_t> bin_digest = digest();
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (uint8_t b : bin_digest) {
            oss << std::setw(2) << static_cast<unsigned>(b);
        }
        return oss.str();
    }
private:
    void do_finalize() {
        if (finalized) return;
        uint64_t total_bits = (total_bytes + buffer.size()) * 8;
        buffer.push_back(0x80);
        size_t orig_size = buffer.size();
        size_t padding_len = (orig_size % 64 < 56) ? (56 - orig_size % 64) : (120 - orig_size % 64);
        buffer.resize(orig_size + padding_len, 0);
        for (int i = 0; i < 8; ++i) {
            buffer.push_back(static_cast<uint8_t>((total_bits >> (56 - i * 8)) & 0xFF));
        }
        for (size_t i = 0; i < buffer.size(); i += 64) {
            process_block(&buffer[i]);
        }
        finalized = true;
        buffer.clear();
    }
};

// ================= SHA384 =================

class SHA384 {
private:
    uint64_t h[8];
    uint64_t length;
    uint8_t buffer[128];
    size_t buffer_size;
    bool finalized;

    // 64位循环右移
    inline uint64_t rotr64(uint64_t x, uint32_t n) {
        return (x >> n) | (x << (64 - n));
    }

    // SHA-384逻辑函数
    inline uint64_t ch(uint64_t x, uint64_t y, uint64_t z) {
        return (x & y) ^ (~x & z);
    }

    inline uint64_t maj(uint64_t x, uint64_t y, uint64_t z) {
        return (x & y) ^ (x & z) ^ (y & z);
    }

    inline uint64_t sigma0(uint64_t x) {
        return rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39);
    }

    inline uint64_t sigma1(uint64_t x) {
        return rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41);
    }

    inline uint64_t gamma0(uint64_t x) {
        return rotr64(x, 1) ^ rotr64(x, 8) ^ (x >> 7);
    }

    inline uint64_t gamma1(uint64_t x) {
        return rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6);
    }

    // 处理一个128字节块
    void process_block(const uint8_t* block) {
        uint64_t w[80] = {0};
        
        // 加载前16个字(大端序)
        for (int i = 0; i < 16; ++i) {
            w[i] = (static_cast<uint64_t>(block[i*8]) << 56) |
                   (static_cast<uint64_t>(block[i*8+1]) << 48) |
                   (static_cast<uint64_t>(block[i*8+2]) << 40) |
                   (static_cast<uint64_t>(block[i*8+3]) << 32) |
                   (static_cast<uint64_t>(block[i*8+4]) << 24) |
                   (static_cast<uint64_t>(block[i*8+5]) << 16) |
                   (static_cast<uint64_t>(block[i*8+6]) << 8) |
                   (static_cast<uint64_t>(block[i*8+7]));
        }
        
        // 扩展消息调度数组(16-79)
        for (int i = 16; i < 80; ++i) {
            w[i] = gamma1(w[i-2]) + w[i-7] + gamma0(w[i-15]) + w[i-16];
        }
        
        // 初始化工作变量
        uint64_t a = h[0];
        uint64_t b = h[1];
        uint64_t c = h[2];
        uint64_t d = h[3];
        uint64_t e = h[4];
        uint64_t f = h[5];
        uint64_t g = h[6];
        uint64_t h_val = h[7];
        
        // 主循环(80轮)
        for (int i = 0; i < 80; ++i) {
            uint64_t t1 = h_val + sigma1(e) + ch(e, f, g) + k[i] + w[i];
            uint64_t t2 = sigma0(a) + maj(a, b, c);
            
            h_val = g;
            g = f;
            f = e;
            e = d + t1;
            d = c;
            c = b;
            b = a;
            a = t1 + t2;
        }
        
        // 更新哈希值
        h[0] += a;
        h[1] += b;
        h[2] += c;
        h[3] += d;
        h[4] += e;
        h[5] += f;
        h[6] += g;
        h[7] += h_val;
    }

    // SHA-384常量
    static const uint64_t k[80];

public:
    SHA384() {
        reset();
    }

    // 重置哈希计算状态
    void reset() {
        // SHA-384初始哈希值
        h[0] = 0xcbbb9d5dc1059ed8;
        h[1] = 0x629a292a367cd507;
        h[2] = 0x9159015a3070dd17;
        h[3] = 0x152fecd8f70e5939;
        h[4] = 0x67332667ffc00b31;
        h[5] = 0x8eb44a8768581511;
        h[6] = 0xdb0c2e0d64f98fa7;
        h[7] = 0x47b5481dbefa4fa4;
        
        length = 0;
        buffer_size = 0;
        finalized = false;
    }

    // 更新哈希计算(原始内存数据)
    void update(const void* data, size_t size) {
        if (finalized) return;
        const uint8_t* input = static_cast<const uint8_t*>(data);
        size_t offset = 0;
        
        // 处理缓冲区中已有的数据
        if (buffer_size > 0) {
            size_t copy_len = std::min(128 - buffer_size, size);
            memcpy(buffer + buffer_size, input, copy_len);
            buffer_size += copy_len;
            offset += copy_len;
            
            if (buffer_size == 128) {
                process_block(buffer);
                length += 128;
                buffer_size = 0;
            }
        }
        
        // 处理完整的块
        while (offset + 128 <= size) {
            process_block(input + offset);
            length += 128;
            offset += 128;
        }
        
        // 将剩余数据存入缓冲区
        if (offset < size) {
            size_t remaining = size - offset;
            memcpy(buffer, input + offset, remaining);
            buffer_size = remaining;
        }
    }

    // 更新哈希计算(字节向量)
    void update(const std::vector<uint8_t>& data) {
        update(data.data(), data.size());
    }

    // 更新哈希计算(字符串)
    void update(const std::string& data) {
        update(data.data(), data.size());
    }

    void finalize() {
        if (!finalized) do_finalize();
    }

    // 完成哈希计算并返回十六进制摘要
    std::string hexdigest() {
        if (!finalized) do_finalize();
        // 生成十六进制摘要(取前384位,即前6个64位字)
        std::stringstream ss;
        ss << std::hex << std::setfill('0');
        for (int i = 0; i < 6; ++i) {
            for (int j = 7; j >= 0; --j) {
                uint8_t byte = static_cast<uint8_t>((h[i] >> (j * 8)) & 0xFF);
                ss << std::setw(2) << static_cast<unsigned>(byte);
            }
        }
        
        // 重置状态以便后续使用
        reset();
        
        return ss.str();
    }

    // 完成哈希计算并返回二进制摘要
    std::vector<uint8_t> digest() {
        if (!finalized) do_finalize();
        // 获取十六进制摘要
        std::string hex = hexdigest();
        
        // 转换为二进制数据
        std::vector<uint8_t> bin;
        bin.reserve(48); // SHA-384产生48字节摘要
        
        for (size_t i = 0; i < hex.length(); i += 2) {
            unsigned int byte;
            std::stringstream ss;
            ss << std::hex << hex.substr(i, 2);
            ss >> byte;
            bin.push_back(static_cast<uint8_t>(byte));
        }
        
        return bin;
    }

private:
    void do_finalize() {
        if (finalized) return;
        // 保存原始长度
        uint64_t original_length = length + buffer_size;
        uint64_t original_bits = original_length * 8;
        
        // 添加填充
        size_t padding_len = (buffer_size < 112) ? (112 - buffer_size) : (240 - buffer_size);
        std::vector<uint8_t> padding(padding_len + 16);
        padding[0] = 0x80;
        
        // 添加长度信息(大端序)
        for (int i = 0; i < 8; ++i) {
            padding[padding_len + 8 + i] = static_cast<uint8_t>(original_bits >> (56 - i * 8));
        }
        
        // 处理填充数据
        update(padding.data(), padding.size());
        finalized = true;
    }
};

// 定义SHA-384常量
const uint64_t SHA384::k[80] = {
    0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
    0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
    0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
    0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
    0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
    0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
    0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
    0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
    0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
    0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
    0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
    0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
    0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
    0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
    0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
    0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
    0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
    0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
    0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
    0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};

// ================= SHA512 =================
class SHA512 {
private:
    uint64_t total_bytes[2];
    std::vector<uint8_t> buffer;
    uint64_t h[8];
    bool finalized;
    static const uint64_t K[80];
    static inline uint64_t ROTR(uint64_t x, uint64_t n) {
        return (x >> n) | (x << (64 - n));
    }
    static inline uint64_t Ch(uint64_t x, uint64_t y, uint64_t z) {
        return (x & y) ^ (~x & z);
    }
    static inline uint64_t Maj(uint64_t x, uint64_t y, uint64_t z) {
        return (x & y) ^ (x & z) ^ (y & z);
    }
    static inline uint64_t Sigma0(uint64_t x) {
        return ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39);
    }
    static inline uint64_t Sigma1(uint64_t x) {
        return ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41);
    }
    static inline uint64_t sigma0(uint64_t x) {
        return ROTR(x, 1) ^ ROTR(x, 8) ^ (x >> 7);
    }
    static inline uint64_t sigma1(uint64_t x) {
        return ROTR(x, 19) ^ ROTR(x, 61) ^ (x >> 6);
    }
    void process_block(const uint8_t* block) {
        uint64_t w[80] = { 0 };
        for (int i = 0; i < 16; i++) {
            for (int j = 0; j < 8; j++) {
                w[i] = (w[i] << 8) | static_cast<uint64_t>(block[i * 8 + j]);
            }
        }
        for (int i = 16; i < 80; i++) {
            w[i] = sigma1(w[i - 2]) + w[i - 7] + sigma0(w[i - 15]) + w[i - 16];
        }
        uint64_t a = h[0], b = h[1], c = h[2], d = h[3];
        uint64_t e = h[4], f = h[5], g = h[6], h_val = h[7];
        for (int i = 0; i < 80; i++) {
            uint64_t T1 = h_val + Sigma1(e) + Ch(e, f, g) + K[i] + w[i];
            uint64_t T2 = Sigma0(a) + Maj(a, b, c);
            h_val = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
        }
        h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; h[5] += f; h[6] += g; h[7] += h_val;
    }
public:
    SHA512() { reset(); }
    void reset() {
        h[0] = 0x6a09e667f3bcc908;
        h[1] = 0xbb67ae8584caa73b;
        h[2] = 0x3c6ef372fe94f82b;
        h[3] = 0xa54ff53a5f1d36f1;
        h[4] = 0x510e527fade682d1;
        h[5] = 0x9b05688c2b3e6c1f;
        h[6] = 0x1f83d9abfb41bd6b;
        h[7] = 0x5be0cd19137e2179;
        total_bytes[0] = 0;
        total_bytes[1] = 0;
        buffer.clear();
        finalized = false;
    }
    void update(const void* data, size_t len) {
        if (finalized) {
            throw std::runtime_error("SHA512: cannot update after finalization");
        }
        const uint8_t* d = static_cast<const uint8_t*>(data);
        size_t index = 0;
        uint64_t prev_total = total_bytes[1];
        total_bytes[1] += static_cast<uint64_t>(len);
        if (total_bytes[1] < prev_total) {
            total_bytes[0]++;
        }
        if (!buffer.empty()) {
            size_t remaining = 128 - buffer.size();
            if (len < remaining) {
                buffer.insert(buffer.end(), d, d + len);
                return;
            }
            buffer.insert(buffer.end(), d, d + remaining);
            process_block(buffer.data());
            index = remaining;
            len -= remaining;
            buffer.clear();
        }
        while (len - index >= 128) {
            process_block(d + index);
            index += 128;
        }
        if (index < len) {
            buffer.insert(buffer.end(), d + index, d + len);
        }
    }
    void update(const std::string& data) { update(data.data(), data.size()); }
    void update(const std::vector<uint8_t>& data) { update(data.data(), data.size()); }
    void finalize() {
        if (!finalized) do_finalize();
    }
    std::vector<uint8_t> digest() {
        if (!finalized) do_finalize();
        std::vector<uint8_t> result(64);
        for (int i = 0; i < 8; i++) {
            for (int j = 7; j >= 0; j--) {
                result[i * 8 + (7 - j)] = static_cast<uint8_t>((h[i] >> (j * 8)) & 0xFF);
            }
        }
        return result;
    }
    std::string hexdigest() {
        std::vector<uint8_t> bin_digest = digest();
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (uint8_t b : bin_digest) {
            oss << std::setw(2) << static_cast<unsigned>(b);
        }
        return oss.str();
    }
private:
    void do_finalize() {
        if (finalized) return;
        uint64_t total_bits_low = total_bytes[1] << 3;
        uint64_t total_bits_high = (total_bytes[0] << 3) | (total_bytes[1] >> 61);
        buffer.push_back(0x80);
        size_t orig_size = buffer.size();
        size_t padding_len = (orig_size % 128 < 112) ? (112 - orig_size % 128) : (240 - orig_size % 128);
        buffer.insert(buffer.end(), padding_len, 0);
        for (int i = 7; i >= 0; --i) {
            buffer.push_back(static_cast<uint8_t>((total_bits_high >> (i * 8)) & 0xFF));
        }
        for (int i = 7; i >= 0; --i) {
            buffer.push_back(static_cast<uint8_t>((total_bits_low >> (i * 8)) & 0xFF));
        }
        size_t i = 0;
        while (i + 128 <= buffer.size()) {
            process_block(&buffer[i]);
            i += 128;
        }
        finalized = true;
        buffer.clear();
    }
};
const uint64_t SHA512::K[80] = {
    0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
    0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
    0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
    0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
    0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
    0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
    0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
    0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
    0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
    0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
    0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
    0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
    0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
    0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
    0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
    0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
    0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
    0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
    0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
    0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};

2. 使用示例

这里给一个测试代码和使用demo,测试代码:

#include "hash.hpp"
#include <iostream>
#include <string>
#include <cassert>
#include <vector>

using namespace std;

// 测试 MD5 算法
void test_md5() {
    cout << "Testing MD5..." << endl;
    
    // 测试空字符串
    MD5 md5_empty;
    md5_empty.update("");
    assert(md5_empty.hexdigest() == "d41d8cd98f00b204e9800998ecf8427e");
    cout << "Empty string: PASS" << endl;
    
    // 测试 "abc"
    MD5 md5_abc;
    md5_abc.update("abc");
    assert(md5_abc.hexdigest() == "900150983cd24fb0d6963f7d28e17f72");
    cout << "\"abc\": PASS" << endl;
    
    // 测试长字符串
    MD5 md5_long;
    md5_long.update("The quick brown fox jumps over the lazy dog");
    assert(md5_long.hexdigest() == "9e107d9d372bb6826bd81d3542a419d6");
    cout << "Long string: PASS" << endl;
    
    // 测试分块更新
    MD5 md5_chunk;
    md5_chunk.update("The quick brown fox ");
    md5_chunk.update("jumps over the lazy dog");
    assert(md5_chunk.hexdigest() == "9e107d9d372bb6826bd81d3542a419d6");
    cout << "Chunked update: PASS" << endl;
    
    cout << "MD5 tests completed successfully!" << endl << endl;
}

// 测试 SHA1 算法
void test_sha1() {
    cout << "Testing SHA1..." << endl;
    
    // 测试空字符串
    SHA1 sha1_empty;
    sha1_empty.update("");
    assert(sha1_empty.hexdigest() == "da39a3ee5e6b4b0d3255bfef95601890afd80709");
    cout << "Empty string: PASS" << endl;
    
    // 测试 "abc"
    SHA1 sha1_abc;
    sha1_abc.update("abc");
    assert(sha1_abc.hexdigest() == "a9993e364706816aba3e25717850c26c9cd0d89d");
    cout << "\"abc\": PASS" << endl;
    
    // 测试长字符串
    SHA1 sha1_long;
    sha1_long.update("The quick brown fox jumps over the lazy dog");
    assert(sha1_long.hexdigest() == "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
    cout << "Long string: PASS" << endl;
    
    // 测试分块更新
    SHA1 sha1_chunk;
    sha1_chunk.update("The quick brown fox ");
    sha1_chunk.update("jumps over the lazy dog");
    assert(sha1_chunk.hexdigest() == "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12");
    cout << "Chunked update: PASS" << endl;
    
    cout << "SHA1 tests completed successfully!" << endl << endl;
}

// 测试 SHA256 算法
void test_sha256() {
    cout << "Testing SHA256..." << endl;
    
    // 测试空字符串
    SHA256 sha256_empty;
    sha256_empty.update("");
    assert(sha256_empty.hexdigest() == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
    cout << "Empty string: PASS" << endl;
    
    // 测试 "abc"
    SHA256 sha256_abc;
    sha256_abc.update("abc");
    assert(sha256_abc.hexdigest() == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
    cout << "\"abc\": PASS" << endl;
    
    // 测试长字符串
    SHA256 sha256_long;
    sha256_long.update("The quick brown fox jumps over the lazy dog");
    assert(sha256_long.hexdigest() == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592");
    cout << "Long string: PASS" << endl;
    
    // 测试分块更新
    SHA256 sha256_chunk;
    sha256_chunk.update("The quick brown fox ");
    sha256_chunk.update("jumps over the lazy dog");
    assert(sha256_chunk.hexdigest() == "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592");
    cout << "Chunked update: PASS" << endl;
    
    cout << "SHA256 tests completed successfully!" << endl << endl;
}

// 测试 SHA384 算法
void test_sha384() {
    cout << "Testing SHA384..." << endl;
    
    // 测试空字符串
    SHA384 sha384_empty;
    sha384_empty.update("");
    assert(sha384_empty.hexdigest() == "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b");
    cout << "Empty string: PASS" << endl;
    
    // 测试 "abc"
    SHA384 sha384_abc;
    sha384_abc.update("abc");
    assert(sha384_abc.hexdigest() == "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7");
    cout << "\"abc\": PASS" << endl;
    
    // 测试长字符串
    SHA384 sha384_long;
    sha384_long.update("The quick brown fox jumps over the lazy dog");
    assert(sha384_long.hexdigest() == "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1");
    cout << "Long string: PASS" << endl;
    
    // 测试分块更新
    SHA384 sha384_chunk;
    sha384_chunk.update("The quick brown fox ");
    sha384_chunk.update("jumps over the lazy dog");
    assert(sha384_chunk.hexdigest() == "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1");
    cout << "Chunked update: PASS" << endl;
    
    cout << "SHA384 tests completed successfully!" << endl << endl;
}

// 测试 SHA512 算法
void test_sha512() {
    cout << "Testing SHA512..." << endl;
    
    // 测试空字符串
    SHA512 sha512_empty;
    sha512_empty.update("");
    assert(sha512_empty.hexdigest() == "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
    cout << "Empty string: PASS" << endl;
    
    // 测试 "abc"
    SHA512 sha512_abc;
    sha512_abc.update("abc");
    assert(sha512_abc.hexdigest() == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
    cout << "\"abc\": PASS" << endl;
    
    // 测试长字符串
    SHA512 sha512_long;
    sha512_long.update("The quick brown fox jumps over the lazy dog");
    assert(sha512_long.hexdigest() == "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6");
    cout << "Long string: PASS" << endl;
    
    // 测试分块更新
    SHA512 sha512_chunk;
    sha512_chunk.update("The quick brown fox ");
    sha512_chunk.update("jumps over the lazy dog");
    assert(sha512_chunk.hexdigest() == "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6");
    cout << "Chunked update: PASS" << endl;
    
    cout << "SHA512 tests completed successfully!" << endl << endl;
}

int main() {
    try {
        test_md5();
        test_sha1();
        test_sha256();
        test_sha384();
        test_sha512();
        
        cout << "All tests passed!" << endl;
        system("pause");
        return 0;
    } catch (const exception& e) {
        cerr << "Test failed: " << e.what() << endl;
        system("pause");
        return 1;
    }
}

正常情况下输出像这样(本人使用MinGW 4.9.2,C++14标准):

使用demo:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iomanip>
#include "hash.hpp"

// 函数声明
void print_usage(const char* program_name);
std::vector<uint8_t> read_file(const std::string& filename);
void calculate_hash(const std::string& algorithm, const std::vector<uint8_t>& data);

int main(int argc, char* argv[]) {
    // 检查参数数量
    if (argc != 3) {
        print_usage(argv[0]);
        return 1;
    }

    std::string algorithm = argv[1];
    std::string filename = argv[2];

    // 转换为大写以便比较
    for (char& c : algorithm) {
        c = std::toupper(c);
    }

    // 读取文件
    std::vector<uint8_t> file_data;
    try {
        file_data = read_file(filename);
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return 1;
    }

    // 计算哈希值
    try {
        calculate_hash(algorithm, file_data);
    } catch (const std::exception& e) {
        std::cerr << "错误: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

void print_usage(const char* program_name) {
    std::cout << "用法: " << program_name << " <算法> <文件名>" << std::endl;
    std::cout << "支持的算法: MD5, SHA1, SHA256, SHA384, SHA512" << std::endl;
    std::cout << "示例: " << program_name << " MD5 example.txt" << std::endl;
}

std::vector<uint8_t> read_file(const std::string& filename) {
    std::ifstream file(filename, std::ios::binary);
    if (!file) {
        throw std::runtime_error("无法打开文件: " + filename);
    }

    // 获取文件大小
    file.seekg(0, std::ios::end);
    std::streamsize size = file.tellg();
    file.seekg(0, std::ios::beg);

    // 读取文件内容
    std::vector<uint8_t> buffer(size);
    if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
        throw std::runtime_error("读取文件失败: " + filename);
    }

    return buffer;
}

void calculate_hash(const std::string& algorithm, const std::vector<uint8_t>& data) {
    if (algorithm == "MD5") {
        MD5 md5;
        md5.update(data);
        std::cout << "MD5: " << md5.hexdigest() << std::endl;
    } else if (algorithm == "SHA1") {
        SHA1 sha1;
        sha1.update(data);
        std::cout << "SHA1: " << sha1.hexdigest() << std::endl;
    } else if (algorithm == "SHA256") {
        SHA256 sha256;
        sha256.update(data);
        std::cout << "SHA256: " << sha256.hexdigest() << std::endl;
    } else if (algorithm == "SHA384") {
        SHA384 sha384;
        sha384.update(data);
        std::cout << "SHA384: " << sha384.hexdigest() << std::endl;
    } else if (algorithm == "SHA512") {
        SHA512 sha512;
        sha512.update(data);
        std::cout << "SHA512: " << sha512.hexdigest() << std::endl;
    } else {
        throw std::runtime_error("不支持的算法: " + algorithm);
    }
}

这是一个文件哈希计算工具,需要命令行传参,第一个参数是算法名,第二个参数是文件名。

三、哈希碰撞漏洞

前面讲了哈希值很难重复,但并不代表不可能,这就被称为碰撞漏洞。比如下面两个字符串:

d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70

和:

d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f965ab6ff72a70

就是一个经典的MD5碰撞漏洞,它们的MD5值就是一样的。

这俩字符串乍一看一摸一样,但只不过差别很小,很难看出来:

根本就不一样,而且它们的MD5值都是79054025255fb1a26e4bc422aef54eb4。

好了,本文到此结束!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐