一、SHA256算法介绍
  SHA256算法总体上来说就是对原始数据进行分段加密,并且当前分段的加密结果受到上一分段加密结果的影响,最后一段的加密结果就是最终的结果(和混沌系统有点类似)。

二、SHA256算法C++实现
1)sha256.h

/*
 * Copyright (c)
 * Filename:    sha256.h
 * Brief:       SHA256算法实现
 * Depend:      C++11
 *
 * Version:     V1.0.0
 * Date:        2019/11/08-2019/11/13
 * Author:      LucianY
 * Note:        初次版本。
 * 
 * Version:     V2.0.0
 * Date:        2023/01/04
 * Author:      LucianY
 * Note:        1、代码优化:使用单例模式;
 *              2、debug:支持加密空字符串;
 *              3、性能优化。
 * 
 * Attention:   输入信息中有中文时,得到的数字指纹与使用其他工具得到数字指纹可能不相同。原因是不同平台中文的编码方式不同。
 */

#ifndef LY_SHA256_H
#define LY_SHA256_H

#include <cstdint>

#include <string>
#include <vector>

namespace Ly {

/**
 * @brief SHA256加密类
*/
class Sha256 {
public:
    //! 获取单例
    inline static Sha256 &getInstance()
    {
        static Sha256 instance;
        return instance;
    }

    /** 
     * @brief: 使用SHA256算法,加密输入信息(获取数字指纹)
     * @param[in] message: 输入信息
     * @return: 摘要(数字指纹)
    */
    std::vector<uint8_t> encrypt(std::vector<uint8_t> message) const;

    /** 
     * @brief: 获取十六进制表示的信息摘要(数字指纹)
     * @param[in] message: 输入信息
     * @return: 十六进制表示的信息摘要(数字指纹)
    */
    std::string getHexMessageDigest(const std::string &message) const;

protected:
    /// SHA256算法中定义的6种逻辑运算 ///

    inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) const noexcept
    {
        return (x & y) ^ ((~x) & z);
    }

    inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) const noexcept
    {
        return (x & y) ^ (x & z) ^ (y & z);
    }

    inline uint32_t bigSigma0(uint32_t x) const noexcept
    {
        return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10);
    }

    inline uint32_t bigSigma1(uint32_t x) const noexcept
    {
        return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7);
    }

    inline uint32_t smallSigma0(uint32_t x) const noexcept
    {
        return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3);
    }

    inline uint32_t smallSigma1(uint32_t x) const noexcept
    {
        return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10);
    }

    /** 
     * @brief: SHA256算法对输入信息的预处理,包括“附加填充比特”和“附加长度值”
            附加填充比特: 在报文末尾进行填充,先补第一个比特为1,然后都补0,直到长度满足对512取模后余数是448。需要注意的是,信息必须进行填充。
            附加长度值: 用一个64位的数据来表示原始消息(填充前的消息)的长度,并将其补到已经进行了填充操作的消息后面。
     * @param[in][out] message: 待处理的信息
    */
    void preprocessing(std::vector<uint8_t> &message) const;

    /** 
     * @brief: 将信息分解成连续的64Byte大小的数据块
     * @param[in] message: 输入信息,长度为64Byte的倍数
     * @return: 输出数据块
    */
    std::vector<std::vector<uint8_t>> breakTextInto64ByteChunks(const std::vector<uint8_t> &message) const;

    /** 
     * @brief: 由64Byte大小的数据块,构造出64个4Byte大小的字。
            构造算法:前16个字直接由数据块分解得到,其余的字由如下迭代公式得到:
            W[t] = smallSigma1(W[t-2]) + W[t-7] + smallSigma0(W[t-15]) + W[t-16]
     * @param[in] chunk: 输入数据块,大小为64Byte
     * @return: 输出字
    */
    std::vector<uint32_t> structureWords(const std::vector<uint8_t> &chunk) const;

    /** 
     * @breif: 基于64个4Byte大小的字,进行64次循环加密
     * @param[in] words: 64个4Byte大小的字
     * @param[in][out] message_digest: 信息摘要
    */
    void transform(const std::vector<uint32_t> &words, std::vector<uint32_t> &message_digest) const;

    /** 
     * @brief: 输出最终的哈希值(数字指纹)
     * @param[in] input: 步长为32bit的哈希值
     * @return: 步长为8bit的哈希值
    */
    std::vector<uint8_t> produceFinalHashValue(const std::vector<uint32_t> &input) const;

private:
    /* 单例模式 */
    Sha256() = default;

    Sha256(const Sha256 &) = delete;
    Sha256 &operator=(const Sha256 &) = delete;

    Sha256(Sha256 &&) = delete;
    Sha256 &operator=(Sha256 &&) = delete;

    ~Sha256() = default;


    // 在SHA256算法中的初始信息摘要,这些常量是对自然数中前8个质数的平方根的小数部分取前32bit而来
    static const std::vector<uint32_t> initial_message_digest_;

    // 在SHA256算法中,用到64个常量,这些常量是对自然数中前64个质数的立方根的小数部分取前32bit而来
    static const std::vector<uint32_t> add_constant_;
};

} // namespace Ly
#endif // LY_SHA256_H

2)sha256.cpp

/*
 * Copyright (c)
 * Filename:    sha256.cpp
 * Brief:       SHA256算法实现
 * Depend:      C++11
 *
 * Version:     V1.0.0
 * Date:        2019/11/08-2019/11/13
 * Author:      LucianY
 * Note:        初次版本。
 * 
 * Version:     V2.0.0
 * Date:        2023/01/04
 * Author:      LucianY
 * Note:        1、代码优化:使用单例模式;
 *              2、debug:支持加密空字符串;
 *              3、性能优化。
 * 
 * Attention:   输入信息中有中文时,得到的数字指纹与使用其他工具得到数字指纹可能不相同。原因是不同平台中文的编码方式不同。
 */

#include "sha256.h"

#include <iomanip>
#include <sstream>
#include <string>
#include <vector>

namespace Ly {

const std::vector<uint32_t> Sha256::initial_message_digest_{
    0x6a09e667, 0xbb67ae85, 0x3c6ef372,
    0xa54ff53a, 0x510e527f, 0x9b05688c,
    0x1f83d9ab, 0x5be0cd19
};

const std::vector<uint32_t> Sha256::add_constant_{
    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::vector<uint8_t> Sha256::encrypt(std::vector<uint8_t> input_message) const
{
    //! 文本预处理
    preprocessing(input_message);

    //! 将文本分解成连续的64Byte大小的数据块
    auto chunks = breakTextInto64ByteChunks(input_message);

    //! 由64Byte大小的数据块,构造出64个4Byte大小的字。然后进行循环迭代。
    std::vector<uint32_t> message_digest(initial_message_digest_); // 初始化信息摘要
    for (const auto &chunk : chunks)
    {
        transform(structureWords(chunk), message_digest);
    }

    //! 获取最终结果
    return produceFinalHashValue(message_digest);
}

std::string Sha256::getHexMessageDigest(const std::string &message) const
{
    auto digest = encrypt(std::vector<uint8_t>(message.begin(), message.end()));

    std::ostringstream o_s;
    o_s << std::hex << std::setiosflags(std::ios::uppercase);
    for (auto c : digest) {
        o_s << std::setw(2) << std::setfill('0') << static_cast<unsigned short>(c);
    }

    return o_s.str();
}

void Sha256::preprocessing(std::vector<uint8_t> &message) const
{
    const auto original_bit_size = message.size() * 8;

    //! 附加填充比特
    auto remainder = message.size() % 64;
    auto origialSize = message.size();
    if (remainder < 56)
    {
        message.resize(message.size() + 56 - remainder, 0x00);
        message[origialSize] = 0x80; // ox80即10000000
    } 
    else if (remainder == 56)
    {
        message.resize(message.size() + 64, 0x00);
        message[origialSize] = 0x80;
    } 
    else
    {
        message.resize(message.size() + 120 - remainder, 0x00);
        message[origialSize] = 0x80;
    }

    //! 附加原始文本的长度值
    for (int i = 1; i <= 8; ++i)
    {
        message.emplace_back(static_cast<uint8_t>(original_bit_size >> (64 - 8 * i)));
    }
}

std::vector<std::vector<uint8_t>> Sha256::breakTextInto64ByteChunks(const std::vector<uint8_t> &message) const
{
    if (0 != message.size() % 64)
    {
        std::ostringstream oss;
        oss << "invalid message size: " << message.size();
        throw std::invalid_argument(oss.str());
    }

    std::vector<std::vector<uint8_t>> chunks;
    auto quotient = message.size() / 64;
    for (size_t i = 0; i < quotient; ++i)
    {
        chunks.emplace_back(message.begin() + i * 64, message.begin() + (i + 1) * 64);
    }
    return chunks;
}

std::vector<uint32_t> Sha256::structureWords(const std::vector<uint8_t> &chunk) const
{
    if (64 != chunk.size())
    {
        std::ostringstream oss;
        oss << "invalid chunk size: " << chunk.size();
        throw std::invalid_argument(oss.str());
    }

    std::vector<uint32_t> words(64);
    for (size_t i = 0; i < 16; ++i)
    {
        words[i] = (static_cast<uint32_t>(chunk[i * 4]) << 24) | (static_cast<uint32_t>(chunk[i * 4 + 1]) << 16) | 
            (static_cast<uint32_t>(chunk[i * 4 + 2]) << 8) | static_cast<uint32_t>(chunk[i * 4 + 3]);
    }
    for (size_t i = 16; i < 64; ++i)
    {
        words[i] = smallSigma1(words[i - 2]) + words[i - 7] + smallSigma0(words[i - 15]) + words[i - 16];
    }
    return words;
}

void Sha256::transform(const std::vector<uint32_t> &words, std::vector<uint32_t> &message_digest) const
{
    if (8 != message_digest.size() || 64 != words.size())
    {
        std::ostringstream oss;
        oss << "invalid message_digest size: " << message_digest.size() << 
            "Or invalid words size: " << words.size();
        throw std::invalid_argument(oss.str());
    }

    auto d = message_digest;
    for (int i = 0; i < 64; ++i)
    {
        uint32_t temp1 = d[7] + bigSigma1(d[4]) + ch(d[4], d[5], d[6]) + add_constant_[i] + words[i];
        uint32_t temp2 = bigSigma0(d[0]) + maj(d[0], d[1], d[2]);

        d[7] = d[6];
        d[6] = d[5];
        d[5] = d[4];
        d[4] = d[3] + temp1;
        d[3] = d[2];
        d[2] = d[1];
        d[1] = d[0];
        d[0] = temp1 + temp2;
    }

    for (int i = 0; i < 8; ++i)
    {
        message_digest[i] += d[i];
    }
}

std::vector<uint8_t> Sha256::produceFinalHashValue(const std::vector<uint32_t> &input) const
{
    std::vector<uint8_t> output;
    for (auto it = input.begin(); it != input.end(); ++it)
    {
        for (int i = 0; i < 4; i++)
        {
            output.emplace_back(static_cast<uint8_t>((*it) >> (24 - 8 * i)));
        }
    }

    return output;
}

} // namespace Ly

3)main.cpp

/*
* Filename: main.cpp
* Author: L.Y.
* Brief: SHA256算法测试
*/

#include <iostream>
#include <string>

#include "sha256.h"

void testSha256()
{
    //! 输入报文为空报文
    if (true) {
        std::string message; // 待加密的信息
        std::string message_digest = Ly::Sha256::getInstance().getHexMessageDigest(message); // 加密

        // 输出加密结果:E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
        std::cout << '\"' << message << "\" digest is: " << message_digest << std::endl << std::endl;
    }

    //! 输入报文长度小于56
    if (true) {
        std::string message = "seek truth from facts"; // 待加密的信息
        std::string message_digest = Ly::Sha256::getInstance().getHexMessageDigest(message); // 加密

        // 输出加密结果:E2E63CD711B3FE1A6613A54010F4C198894DA5E87517FEFCEE239031A0270CC9
        std::cout << '\"' << message << "\" digest is: " << message_digest << std::endl << std::endl;
    }

    //! 输入报文长度等于56
    if (true) {
        std::string message(56, '@'); // 待加密的信息
        std::string message_digest = Ly::Sha256::getInstance().getHexMessageDigest(message); // 加密

        // 输出加密结果:1081DDB54326E1D17F90857107D2F5C2DE80ACD2A3FC2C57A12DC605FC2CB07D
        std::cout << '\"' << message << "\" digest is: " << message_digest << std::endl << std::endl;
    }

    //! 输入报文长度大于56并且小于64
    if (true) {
        std::string message(60, '#'); // 待加密的信息
        std::string message_digest = Ly::Sha256::getInstance().getHexMessageDigest(message); // 加密

        // 输出加密结果:AFD1B7A7CA681D044AF56BE6B0D2E56066A82E32BBBAAB5BA76A7C93E63E585B
        std::cout << '\"' << message << "\" digest is: " << message_digest << std::endl << std::endl;
    }
}

int main()
{
    testSha256();
    getchar();
	return 0;
}