0

0

c++怎么实现文件的md5校验_c++ 加密库引入与哈希值计算【实战】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-12-26 14:29:39

|

444人浏览过

|

来源于php中文网

原创

最可靠方式是用OpenSSL的EVP_MD_CTX流式计算文件MD5:打开二进制文件,分块读取(如8192字节),调用EVP_DigestUpdate更新上下文,最后EVP_DigestFinal_ex获取摘要并转十六进制字符串。

c++怎么实现文件的md5校验_c++ 加密库引入与哈希值计算【实战】

用 OpenSSL 的 EVP_MD_CTX 计算文件 MD5 最可靠

直接手写 MD5 算法既没必要也不安全,C++ 没有标准库哈希实现,必须依赖外部加密库。OpenSSL 是最成熟、跨平台、被广泛验证的选择,比自己找轻量级 MD5 实现更省心,也避免因字节序、填充规则等细节出错。

关键不是“能不能”,而是“怎么连上 OpenSSL 并正确流式读取大文件”。小文件可以全读进内存,但生产环境常见几 GB 日志或镜像文件,必须边读边更新哈希上下文。

  • Windows 下需链接 libcrypto.lib(不是 libssl.lib),且确保运行时能找到 libcrypto-3.dll 或对应版本
  • Linux/macOS 链接时加 -lcrypto,头文件包含路径需指向 OpenSSL 安装目录(如 /usr/include/openssl
  • 务必调用 EVP_MD_CTX_new()EVP_MD_CTX_free(),别用已废弃的 EVP_MD_CTX_create()

完整流程:打开 → 分块读 → 更新上下文 → 获取摘要

核心是把文件内容当作数据流喂给哈希上下文,而不是一次性加载。OpenSSL 的 EVP_DigestUpdate() 支持任意长度输入,配合 8192 字节缓冲区足够平衡性能与内存占用

#include 
#include 
#include 
#include 
#include 

std::string file_md5(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file.is_open()) return "";

EVP_MD_CTX* ctx = EVP_MD_CTX_new();
if (!ctx) return "";

if (EVP_DigestInit_ex(ctx, EVP_md5(), nullptr) != 1) {
    EVP_MD_CTX_free(ctx);
    return "";
}

std::vectorzuojiankuohaophpcnunsigned charyoujiankuohaophpcn buffer(8192);
while (file.read(reinterpret_castzuojiankuohaophpcnchar*youjiankuohaophpcn(buffer.data()), buffer.size())) {
    size_t bytes_read = static_castzuojiankuohaophpcnsize_tyoujiankuohaophpcn(file.gcount());
    if (EVP_DigestUpdate(ctx, buffer.data(), bytes_read) != 1) {
        EVP_MD_CTX_free(ctx);
        return "";
    }
}

// 处理剩余未满缓冲区的数据
if (file.gcount() > 0) {
    size_t bytes_read = static_castzuojiankuohaophpcnsize_tyoujiankuohaophpcn(file.gcount());
    if (EVP_DigestUpdate(ctx, buffer.data(), bytes_read) != 1) {
        EVP_MD_CTX_free(ctx);
        return "";
    }
}

unsigned char md[EVP_MAX_MD_SIZE];
unsigned int md_len;
if (EVP_DigestFinal_ex(ctx, md, &md_len) != 1) {
    EVP_MD_CTX_free(ctx);
    return "";
}
EVP_MD_CTX_free(ctx);

std::stringstream ss;
for (unsigned int i = 0; i zuojiankuohaophpcn md_len; ++i) {
    ss zuojiankuohaophpcnzuojiankuohaophpcn std::hex zuojiankuohaophpcnzuojiankuohaophpcn std::setw(2) zuojiankuohaophpcnzuojiankuohaophpcn std::setfill('0') zuojiankuohaophpcnzuojiankuohaophpcn static_castzuojiankuohaophpcnintyoujiankuohaophpcn(md[i]);
}
return ss.str();

}

立即学习C++免费学习笔记(深入)”;

Songtell
Songtell

Songtell是第一个人工智能生成的歌曲含义库

下载

常见错误:忘记关闭文件、忽略 gcount()、MD5 值转字符串格式错

很多初版代码在 file.read() 后直接用 buffer.size() 当作实际读取长度,但最后一次读可能只填满部分缓冲区——gcount() 才是真实字节数。漏掉这一步,校验值必然错误,且难以排查。

  • std::ifstream 构造后没检查 is_open(),导致后续 EVP_DigestInit_ex() 成功但输入为空,结果固定为 d41d8cd98f00b204e9800998ecf8427e(空字符串 MD5)
  • sprintf 或手动拼接十六进制字符串,容易越界或大小写不一致;用 std::stringstream + std::hex + std::setw(2) 更稳妥
  • 没在最后调用 EVP_DigestFinal_ex(),或调用后未检查返回值,导致 md 数组内容未定义

替代方案对比:Crypto++ 和 Botan 不如 OpenSSL 省事

如果你已经用着 Crypto++,CryptoPP::MD5 类也能工作,但它的 CalculateDigest() 接口默认要求全部数据在内存中,对大文件要自己分块 + Update(),文档分散且示例少;Botan 的 Botan::HashFunction 设计更现代,但编译依赖更多,Windows 下静态链接容易出符号冲突。

OpenSSL 的优势在于:系统级预装率高(尤其 Linux)、CMake find_package(OpenSSL) 开箱即用、错误码含义明确(查 ERR_get_error() 可定位具体失败点)、社区问题多,搜 "EVP_DigestUpdate file" 就能翻到大量可复用片段。

真正麻烦的从来不是算法本身,而是路径编码(中文路径在 Windows 上要用 std::wifstream + std::codecvt_utf8 转换)、权限不足导致 open 失败、或者磁盘 IO 中断引发的 partial read —— 这些边界情况,比选哪个库重要得多。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

246

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1428

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

606

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

546

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

539

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

156

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

76

2025.08.07

虚拟号码教程汇总
虚拟号码教程汇总

本专题整合了虚拟号码接收验证码相关教程,阅读下面的文章了解更多详细操作。

25

2025.12.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6万人学习

Git 教程
Git 教程

共21课时 | 2.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号