使用CryptoPP AES加密同一文件后文件为空的问题求助
CryptoPP AES加密原文件后变为0字节的原因及解决方法
问题描述
使用CryptoPP实现AES文件加密时,直接对原文件进行读写操作后,文件变为0字节;但将输出指定为不同路径的文件时,加密功能正常。代码如下:
int encrypt_file(std::string file_path, Key& key) { std::ifstream in{file_path, std::ios::binary}; std::ofstream out{file_path, std::ios::binary}; CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption enc{}; const byte* keydata = (const byte*)&key.key[0]; const byte* ivdata = (const byte*)&key.iv[0]; enc.SetKeyWithIV(keydata, key.key.size(), ivdata); CryptoPP::FileSource{ in, true, new CryptoPP::StreamTransformationFilter{enc, new CryptoPP::FileSink{out}}}; std::cout << "finished encrypting"; return 0; }
问题根源
核心问题在于同时以读写模式打开同一个文件时的截断行为:
- 当调用
std::ofstream out{file_path, std::ios::binary}打开文件时,默认会触发文件截断操作——直接清空原文件的所有内容。 - 此时
std::ifstream in还未读取原文件的有效数据,文件就已经被清空,后续读取的是空内容,加密后写入自然得到0字节的文件。 - 当输出路径不同时,原文件不会被截断,
std::ifstream能正常读取原数据,因此加密功能正常。
解决方法
不能直接同时读写同一个文件,必须先完整读取原文件内容,再覆盖写入加密后的结果,以下是两种可行方案:
方案1:内存中转(适合小文件)
先将原文件内容读取到内存,完成加密后再写入原文件:
int encrypt_file(std::string file_path, Key& key) { // 读取原文件到内存 std::ifstream in(file_path, std::ios::binary | std::ios::ate); if (!in.is_open()) { return -1; // 处理文件打开失败 } std::streamsize file_size = in.tellg(); in.seekg(0, std::ios::beg); std::vector<byte> file_data(static_cast<size_t>(file_size)); if (!in.read(reinterpret_cast<char*>(file_data.data()), file_size)) { return -1; // 处理文件读取失败 } in.close(); // 初始化加密器 CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption enc; const byte* keydata = key.key.data(); const byte* ivdata = key.iv.data(); enc.SetKeyWithIV(keydata, key.key.size(), ivdata); // 加密并写入原文件 std::ofstream out(file_path, std::ios::binary); if (!out.is_open()) { return -1; // 处理文件打开失败 } CryptoPP::StringSource(file_data.data(), file_size, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::FileSink(out) ) ); out.close(); std::cout << "finished encrypting"; return 0; }
方案2:临时文件中转(适合大文件)
先将加密结果写入临时文件,验证加密成功后,替换原文件:
#include <cstdio> // 用于remove和rename int encrypt_file(std::string file_path, Key& key) { std::string temp_path = file_path + ".tmp"; // 加密到临时文件 std::ifstream in(file_path, std::ios::binary); std::ofstream out(temp_path, std::ios::binary); if (!in.is_open() || !out.is_open()) { return -1; } CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption enc; const byte* keydata = key.key.data(); const byte* ivdata = key.iv.data(); enc.SetKeyWithIV(keydata, key.key.size(), ivdata); CryptoPP::FileSource(in, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::FileSink(out) ) ); in.close(); out.close(); // 验证临时文件有效性(可选但推荐) std::ifstream temp_check(temp_path, std::ios::binary | std::ios::ate); if (temp_check.tellg() == 0) { remove(temp_path.c_str()); return -1; // 加密失败,删除临时文件 } temp_check.close(); // 替换原文件 remove(file_path.c_str()); rename(temp_path.c_str(), file_path.c_str()); std::cout << "finished encrypting"; return 0; }
注意事项
- 无论采用哪种方案,都要确保原文件读取完成后再执行覆盖写入,避免原文件数据丢失。
- 加密敏感文件前,建议先备份原文件,防止加密过程中出现意外导致数据损坏。
内容的提问来源于stack exchange,提问作者vik24k
相关产品推荐
相关产品推荐

