密码学 - 发布模式下的奇怪行为
Posted
技术标签:
【中文标题】密码学 - 发布模式下的奇怪行为【英文标题】:Cryptography - Bizzare behaviour in Release mode 【发布时间】:2016-08-31 14:09:55 【问题描述】:我有一个使用 Crypto++ 的项目。
Crypto++ 是一个自己的项目,它建立在一个静态库中。 除此之外,我还有另一个大型项目,它使用一些 Crypto++ 类并处理各种算法,它也构建在一个静态库中。
其中两个函数如下:
long long MyClass::EncryptMemory(std::vector<byte> &inOut, char *cPadding, int rounds)
typedef std::numeric_limits<char> CharNumLimit;
char sPadding = 0;
//Calculates padding and returns value as provided type
sPadding = CalcPad<decltype(sPadding)>(reinterpret_cast<MyClassBase*>(m_P)->BLOCKSIZE, static_cast<int>(inOut.size()));
//Push random chars as padding, we never care about padding's content so it doesn't matter what the padding is
for (auto i = 0; i < sPadding; ++i)
inOut.push_back(sRandom(CharNumLimit::min(), CharNumLimit::max()));
std::size_t nSize = inOut.size();
EncryptAdvanced(inOut.data(), nSize, rounds);
if (cPadding)
*cPadding = sPadding;
return nSize;
//Removing the padding is the responsibility of the caller.
//Nevertheless the string is encrypted with padding
//and should here be the right string with a little padding
long long MyClass::DecryptMemory(std::vector<byte> &inOut, int rounds)
DecryptAdvanced(inOut.data(), inOut.size(), rounds);
return inOut.size();
EncryptAdvanced
和 DecryptAdvanced
将参数传递给 Crypto++ 对象。
//...
AdvancedProcessBlocks(bytePtr, nullptr, bytePtr, length, 0);
//...
到目前为止,这些功能完美无缺,几个月以来没有对其进行任何修改。 尽管传递给它们的调用和数据没有改变,但围绕它们的逻辑已经发展。
被加密/解密的数据相当小,但具有动态大小,正在填充if (datasize % BLOCKSIZE)
有余数。
示例:AES Blocksize 为 16。Data 为 31。Padding 为 1。Data 现在为 32。
加密后解密前,字符串与图片相同。
在 调试模式 下运行所有这些显然可以按预期工作。即使在另一台计算机上运行此程序(为 DLL 安装了 VS),它也没有任何区别。数据已正确加密和解密。
尝试在发布模式下运行相同的代码会导致完全不同的加密字符串,而且它不能正确解密 - “垃圾数据”被解密。错误加密或解密的数据是一致的 - 总是相同的垃圾被解密。密钥/密码和轮次/迭代始终相同。
附加信息:数据保存在文件 (ios_base::binary
) 中,并在调试模式下正确处理,来自使用相同静态库 (y/ies) 的同一解决方案中的两个不同程序。
此调试/发布问题的原因可能是什么?
我重新检查了几次 git 历史记录,通过代码调试了几天,但我找不到任何可能导致此问题的原因。 如果有任何信息 - 除了(这里比较不可能)需要MCVE,请留言。
【问题讨论】:
您确定 AdvancedProcessBlocks() 允许就地转换吗?文档说 ProcessBlock() 确实允许这样做,但没有明确说明 AdvancedProcessBlocks() 允许。 ProcessBlock() 是否表现出类似的调试/发布行为?答案可能会提供线索。 @Jeremy 它确实允许。在过去的几个月里,我已经使用并调试了它,没有出现任何问题。这些问题最近才开始出现。到目前为止,没有人对以前的版本有任何问题。我稍后会再次调查并检查可能的原因(/更新问题)。如果我没记错的话,它只发生在图书馆的一次特定调用中。 仔细查看您是如何填充输入向量的。 @JeremyfileIFstream.read(vector.data(), vector.size());
其中大小和(当前)文件位置与加密并写入文件时的位置和大小完全匹配。使用vector.data()
时,unsigned char*
有一个reinterpret_cast
char*
。
【参考方案1】:
显然这是 CryptoPP 中的一个错误。 Rijndael / AES 的最小密钥长度设置为 8 而不是 16。使用 8 字节的无效密钥长度将导致对 Rcon 值的就地数组的越界访问。这个 8 字节的密钥长度目前被报告为有效,必须在 CryptoPP 中修复。
请参阅this issue on github 了解更多信息。 (正在进行的对话)
【讨论】:
哎呀,对于加密库来说,这个实现看起来有点粗心......(我很容易在我的扶手椅上说。)很好地追踪问题。以上是关于密码学 - 发布模式下的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章