You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 19:50:35