aes加密文件需确保密钥强随机、iv每次唯一且随密文存储,密码须经pbkdf2/scrypt派生;读写必须二进制模式,大文件流式处理并pkcs#7填充;跨平台注意字节序与char符号性。

用 AES 加密文件前,先确认你没跳过密钥和 IV 的生成逻辑
直接拿固定字符串当密钥或复用同一个 IV 是最常见翻车点——加密后文件能解,但换台机器、换个时间就失败。AES 要求 IV 每次随机且唯一,密钥必须是强随机字节(不是用户密码明文)。别手写 std::random_device + std::uniform_int_distribution 拼密钥,优先用 OpenSSL 或 libsodium 的 crypto_secretbox_keygen() 这类接口。
-
IV必须随密文一起保存(通常前置 16 字节),解密时原样读出,不能硬编码 - 用户密码 ≠ 密钥:要用
PBKDF2_HMAC_SHA256或scrypt衍生,迭代次数至少 100000 - OpenSSL 的
EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv)中,key和iv都是unsigned char*,长度错一位就段错误
读写大文件时别一次性 fread 到内存,用流式加解密
加密 1GB 文件却申请 1GB 内存?不仅慢,还可能被 OOM kill。AES-CBC 模式要求数据块对齐(16 字节),但文件末尾不足时需 PKCS#7 填充——这必须在流末尾才确定,所以不能边读边写密文,得缓冲最后一块。
- 用
fopen(..., "rb")和fopen(..., "wb"),每次fread(buf, 1, 4096, in),但实际处理按 16 字节块切分 - 最后一块不足 16 字节时,填充字节值等于填充长度(如差 5 字节就填 5 个
0x05),解密后检查并截掉 - 别用
std::ifstream::read读二进制——它可能因 locale 设置误判 EOF,老老实实用 C FILE*
std::ofstream 写密文出错?检查是否漏了 std::ios::binary
Windows 下用文本模式写二进制密文,0x0A 会被悄悄转成 0x0D 0x0A,解密直接失败。错误现象通常是“解密后乱码”或 “padding invalid”。这不是算法问题,是流模式错了。
- 写密文必须:
std::ofstream out("out.enc", std::ios::binary) - 读密文同理:
std::ifstream in("in.enc", std::ios::binary) - 哪怕只用 C 的
fwrite,也要确认fopen是"wb"而非"w" - 用
xxd in.enc | head对比原始和写入后的十六进制,一眼看出换行符污染
跨平台解密失败?重点查 endianness 和 char 符号性
密钥、IV、密文本身是字节流,不涉及大小端,但如果你把 int 类型的长度字段混进文件头(比如先写 4 字节文件原长),那在 x86 和 ARM 上就可能错位。更隐蔽的是 char 默认有无符号——OpenSSL 的 unsigned char* 和某些库的 char* 传参时若编译器解释不同,密钥字节会整体偏移。
立即学习“C++免费学习笔记(深入)”;
- 避免在密文里嵌入任何平台相关类型:长度用
uint32_t(固定 4 字节)+htons()/htonl()网络序 - 所有涉及 OpenSSL 的缓冲区,声明为
unsigned char buf[16],别用char - Linux 和 macOS 默认
char无符号,Windows MSVC 默认有符号——用clang++ -funsigned-char统一
真正卡住人的往往不是 AES 算法本身,而是密钥怎么来、IV 怎么存、文件怎么读、字节怎么解释——这些环节任何一个没对齐,加密就变成单向不可逆。











