AES文件解密报错:invalid PKCS #7 block padding问题求助
解密文件时出现PKCS#7填充错误的解决方案
问题描述
我正在开发一个包含文件加解密功能的项目,处理后文件会被加密并保存为自定义扩展名.lok的文件,格式为「IV#加密文件字节」。解密时遇到报错:"invalid PKCS #7 block padding found in file decryption"。已在.txt文件上测试代码,检查过密钥、IV及加密文件字节,未发现存储导致的异常,附上相关代码,恳请协助解决。
加密函数代码
void encryptFile(const byte* AESkey, const std::string& path) { std::ifstream binaryFile; std::ofstream encryptedFile; std::string encryptedDataBinary; binaryFile.open(path, std::ios::binary); encryptedFile.open(path + ".lok", std::ios::binary); // Initialize with a random IV CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE); CryptoPP::AutoSeededRandomPool prng; prng.GenerateBlock(iv, iv.size()); // Write the IV as raw bytes to the beginning of the encrypted file encryptedFile.write(reinterpret_cast<const char*>(iv.data()), iv.size()); encryptedFile << '#'; // Add the separator // Create AES encryption object CryptoPP::CBC_Mode< CryptoPP::AES >::Encryption e; e.SetKeyWithIV(AESkey, CryptoPP::AES::DEFAULT_KEYLENGTH, iv); // Read the entire file std::string inputData( (std::istreambuf_iterator<char>(binaryFile)), std::istreambuf_iterator<char>() ); // Encrypt the data // The StreamTransformationFilter adds padding // as required. ECB and CBC Mode must be padded // to the block size of the cipher. CryptoPP::StringSource(inputData, true, new CryptoPP::StreamTransformationFilter(e, new CryptoPP::StringSink(encryptedDataBinary))); encryptedFile << encryptedDataBinary; // Close the files binaryFile.close(); encryptedFile.close(); std::remove(path.c_str()); }
解密函数代码
void decryptFile(const byte* AESkey, std::string& path) { std::string decrypted; CryptoPP::SecByteBlock iv(CryptoPP::AES::BLOCKSIZE); std::fstream decryptedFile; std::ifstream encryptedFile; std::stringstream inputData; decryptedFile.open(revertFileExtension(path), std::ios::binary); encryptedFile.open(path); // Read the IV from the beginning of the encrypted file encryptedFile.read(reinterpret_cast<char*>(iv.data()), iv.size()); encryptedFile.rdstate(); // Skip the "#" separator char separator; encryptedFile.read(&separator, 1); // Process the rest of the file (excluding the IV and separator) inputData << encryptedFile.rdbuf(); //decoding hex data to just aes encrypted //decrypting aes CryptoPP::CBC_Mode< CryptoPP::AES >::Decryption d; d.SetKeyWithIV(AESkey, CryptoPP::AES::DEFAULT_KEYLENGTH, iv); // The StreamTransformationFilter removes //padding as required. CryptoPP::StringSource ssd(inputData.str(), true, new CryptoPP::StreamTransformationFilter(d, new CryptoPP::StringSink(decrypted))); decryptedFile << decrypted; // Close the files encryptedFile.close(); decryptedFile.close(); // Remove the original encrypted file std::remove(path.c_str()); }
问题分析与修复方案
核心问题
混合使用二进制/文本模式操作文件:
- 加密时,
encryptedFile以二进制模式打开,但写入分隔符#和加密数据时用了<<文本流运算符,在Windows等系统中会自动转换换行符(比如把\n转成\r\n),破坏二进制加密数据的完整性。 - 解密时,打开加密文件未指定
std::ios::binary,默认文本模式会导致读取二进制数据时丢失或篡改字节,比如将某些控制字符视为文件结束符,导致读取的加密数据不完整,最终触发PKCS#7填充验证失败。
- 加密时,
缺少文件操作的错误检查:读取IV、分隔符等步骤未校验是否成功,若出现读取不完整(比如文件损坏),会使用错误的IV或不完整的加密数据进行解密,直接导致填充错误。
具体修复步骤
1. 统一使用二进制模式读写所有文件
- 解密时打开加密文件需添加
std::ios::binary:encryptedFile.open(path, std::ios::binary); - 加密时写入分隔符和加密数据改用
write方法(二进制写入),避免文本模式转换:// 替换原 encryptedFile << '#' encryptedFile.write("#", 1); // 替换原 encryptedFile << encryptedDataBinary encryptedFile.write(encryptedDataBinary.data(), encryptedDataBinary.size()); - 解密后写入文件也改用
write方法:// 替换原 decryptedFile << decrypted decryptedFile.write(decrypted.data(), decrypted.size());
2. 添加文件操作的错误校验
在读取IV、分隔符后增加检查:
// 读取IV后检查 encryptedFile.read(reinterpret_cast<char*>(iv.data()), iv.size()); if (!encryptedFile) { throw std::runtime_error("读取IV失败"); } // 读取分隔符后检查 char separator; encryptedFile.read(&separator, 1); if (!encryptedFile || separator != '#') { throw std::runtime_error("分隔符无效或读取失败"); }
3. 移除无用代码
解密函数中的encryptedFile.rdstate();只是获取状态但未处理,可删除该语句,改为直接检查读取操作的返回值。
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

