CryptoPP AES-CBC多块加密解密首16字节异常及无填充实现咨询
CryptoPP AES-CBC无填充加密解密问题解决
核心问题分析
你遇到的两个关键问题:
- CBC模式IV未链式更新:CBC加密解密依赖前一个块的密文作为下一个块的IV,你当前每次循环都复用初始IV,导致块间IV不匹配,解密时除最后加密的块外全部乱码。
- 默认填充不符合需求:
StreamTransformationFilter默认启用PKCS#7填充,会自动补全数据到块大小,和你“无需填充”的要求冲突。
解决方案
1. 禁用填充
在StreamTransformationFilter构造时显式指定StreamTransformationFilter::NO_PADDING,关闭自动填充逻辑。
2. 正确维护CBC的IV链式更新
- 加密时:每加密完一个块,将当前密文块设置为下一个块的IV。
- 解密时:每解密完一个块,将当前处理的密文块设置为下一个块的IV。
修正后的代码
加密代码
CryptoPP::SecBlock<CryptoPP::byte> key(reinterpret_cast<const CryptoPP::byte*>("my_superb_key"), CryptoPP::AES::DEFAULT_KEYLENGTH); // 建议明确密钥长度,避免内存垃圾填充 CryptoPP::SecBlock<CryptoPP::byte> iv(reinterpret_cast<const CryptoPP::byte*>("dkdforodosoeosod5"), CryptoPP::AES::BLOCKSIZE); // 加密器初始化移到循环外,避免重复初始化开销 CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc; enc.SetKeyWithIV(key, key.size(), iv, iv.size()); while(i_block != n_block){ CryptoPP::byte* chunk_encrypted = new CryptoPP::byte[sz_chunk]; CryptoPP::ArraySink sink(chunk_encrypted, sz_chunk); // 禁用填充,处理当前数据块 CryptoPP::ArraySource(chunk, sz_chunk, true, new CryptoPP::StreamTransformationFilter(enc, new CryptoPP::Redirector(sink), CryptoPP::StreamTransformationFilter::NO_PADDING // 关键:关闭自动填充 ) ); // 更新IV为当前密文块(CBC下一个块的IV必须是前一个密文) std::memcpy(iv.data(), chunk_encrypted, std::min(sz_chunk, (size_t)CryptoPP::AES::BLOCKSIZE)); // 后续处理加密后的chunk_encrypted,记得用delete[]释放内存 // ... }
解密代码
CryptoPP::SecBlock<CryptoPP::byte> key(reinterpret_cast<const CryptoPP::byte*>("my_superb_key"), CryptoPP::AES::DEFAULT_KEYLENGTH); CryptoPP::SecBlock<CryptoPP::byte> iv(reinterpret_cast<const CryptoPP::byte*>("dkdforodosoeosod5"), CryptoPP::AES::BLOCKSIZE); // 解密器初始化移到循环外 CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec; dec.SetKeyWithIV(key, key.size(), iv, iv.size()); do { CryptoPP::byte* source = new CryptoPP::byte[sz_chunk]; CryptoPP::ArraySink sink(source, sz_chunk); // 禁用填充,处理当前密文块 CryptoPP::ArraySource(dest, sz_chunk, true, new CryptoPP::StreamTransformationFilter(dec, new CryptoPP::Redirector(sink), CryptoPP::StreamTransformationFilter::NO_PADDING // 关键:关闭自动填充 ) ); // 更新IV为当前处理的密文块(解密时CBC下一个块的IV同样是前一个密文) std::memcpy(iv.data(), dest, std::min(sz_chunk, (size_t)CryptoPP::AES::BLOCKSIZE)); // 后续处理解密后的source,记得用delete[]释放内存 // ... } while(/* not done yet */);
注意事项
- 密钥长度:
AES::MAX_KEYLENGTH是32字节(256位),如果你的密钥字符串长度不足,会用内存垃圾填充,建议根据实际密钥长度选择AES::DEFAULT_KEYLENGTH(16字节)或AES::KEYLENGTH_256(32字节)。 - 内存管理:动态分配的
chunk_encrypted和source必须在使用完毕后释放,避免内存泄漏。 - 短块处理:CBC模式支持无填充的短块解密,只要解密时的块大小和加密时完全一致即可正常处理。
内容的提问来源于stack exchange,提问作者user3600124
相关产品推荐
相关产品推荐

