如何使用 crypto++ 计算文件哈希

How to calculate file hash with crypto++

提问人:Jabu 提问时间:10/26/2023 最后编辑:Jabu 更新时间:10/26/2023 访问量:111

问:

我正在尝试将此哈希函数转换为“仅限 c++”并使用 crypto++qt

QString calculateGitHubFileHash(const QString& filePath) 
{
    QFile file(filePath);
    QString shaHash;
    if( file.open(QFile::ReadOnly ) )
    {
        QCryptographicHash hash(QCryptographicHash::Sha1);
        QByteArray header = QString("blob %1").arg(file.size()).toUtf8(); // Need to be null terminated
        hash.addData(header.data(), header.size() + 1);
        hash.addData(file.readAll());

        shaHash = hash.result().toHex();
    }
    return shaHash;
}

一个可重现的工作示例:

#include <curl/curl.h>
#include <regex>
#include <fstream>
#include <cryptopp/sha.h>
#include <cryptopp/hex.h>
#include <cryptopp/filters.h>

static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
    size_t realsize = size * nmemb;
    auto& mem = *static_cast<std::string*>(userp);
    mem.append(static_cast<char*>(contents), realsize);
    return realsize;
}

void curl(std::string& data, const std::string& url)
{
    CURL* curl_handle;
    curl_handle = curl_easy_init();
    curl_easy_setopt(curl_handle, CURLOPT_URL, url.data());
    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &data);
    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "curl/7.55.1");
    curl_easy_perform(curl_handle);
    curl_easy_cleanup(curl_handle);
    curl_global_cleanup();
}

std::string calculateGitHubFileHash(const std::string& filePath) 
{
    std::ifstream file(filePath, std::ios::binary);
    std::string shaHash;
    if (file.is_open())
    {
        // Get the size of the file
        file.seekg(0, std::ios::end);
        std::streamsize size = file.tellg();
        file.seekg(0, std::ios::beg);

        // Calculate the header
        std::string header = "blob " + std::to_string(size);

        // Read the file into a std::vector<byte>
        std::vector<byte> fileContent(size);
        file.read(reinterpret_cast<char*>(&fileContent[0]), size);

        // Calculate the SHA1 hash
        CryptoPP::SHA1 sha1;
        CryptoPP::StringSource(
            header + reinterpret_cast<const char*>(fileContent.data()), 
            true, 
            new CryptoPP::HashFilter(sha1, new CryptoPP::HexEncoder(new CryptoPP::StringSink(shaHash)))
        );
    }
    return shaHash;
}

int main()
{
    std::string json;
    curl(json, "https://api.github.com/repos/jajabu33/test/contents");

    // Using regex to parse the json to reduce code size, as this is just an reproducible example
    std::regex nameRegex("\"name\":\\s*\"(.*?)\"");
    std::regex shaRegex("\"sha\":\\s*\"(.*?)\"");
    std::smatch nameMatches, shaMatches;

    auto nIt = std::sregex_iterator(json.begin(), json.end(), nameRegex);
    auto sIt = std::sregex_iterator(json.begin(), json.end(), shaRegex);

    for (auto itName = nIt, itSha = sIt; itName != std::sregex_iterator() && itSha != std::sregex_iterator(); ++itName, ++itSha)
    {
        nameMatches = *itName;
        shaMatches = *itSha;
        std::string fileName = nameMatches[1];
        std::string sha = shaMatches[1];
        std::string localFileHash = calculateGitHubFileHash("C:/test.txt");
        if (sha != localFileHash)
            std::cout << "File " << fileName << " is not up to date\n";
    }
}

在 GitHub 上,json 哈希正在使用它的本地副本上的函数生成相同的哈希值。test.txt95d09f2b10159347eece71399a7e2e907ea3df4fqttest.txt

但是,用哈希值编写的是calculateGithubFileHashcrypto++07C467E5526EEDE9510953A974DB07F3138AFA57

计算将 blob 标头追加到它的哈希值的正确方法是什么?

C Qt 加密 Crypto++

评论

0赞 Tony J 10/26/2023
这两个相同的文件实际上是二进制文件相同且大小相同吗?你有没有做过任何调试来查看是否和相同?如果不需要对前缀进行哈希处理,请尝试。sizefileContentCryptoPP::FileSourceblob n
0赞 Tony J 10/26/2023
此外,如果它是某处带有“\0”的二进制文件,则由于使用字符串,哈希可能会提前停止,而不是对整个文件进行哈希处理。
0赞 Jabu 10/26/2023
@TonyJ 是的,它们是相同的,需要添加前缀,否则它会与 Github json 上返回的哈希值不匹配,您建议除了“使用字符串”之外还有什么其他方法blobfile
0赞 Tony J 10/26/2023
您是否在测试,在哪里进行测试,并且是相同的?或者你正在测试?Qt版本在标头的末尾有一个'\0'。新版本没有它,因为您正在执行字符串连接。calculateGitHubFileHash(fileA)calculateGitHubFileHash(fileB)fileAfileBcalculateGitHubFileHash(fileA)QtVersion(fileA)
0赞 Tony J 10/26/2023
您可能想尝试一下VectorSource

答: 暂无答案