密码学 - 发布模式下的奇怪行为

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();

EncryptAdvancedDecryptAdvanced 将参数传递给 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 它确实允许。在过去的几个月里,我已经使用并调试了它,没有出现任何问题。这些问题最近才开始出现。到目前为止,没有人对以前的版本有任何问题。我稍后会再次调查并检查可能的原因(/更新问题)。如果我没记错的话,它只发生在图书馆的一次特定调用中。 仔细查看您是如何填充输入向量的。 @Jeremy fileIFstream.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 了解更多信息。 (正在进行的对话)

【讨论】:

哎呀,对于加密库来说,这个实现看起来有点粗心......(我很容易在我的扶手椅上说。)很好地追踪问题。

以上是关于密码学 - 发布模式下的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

systemJS在win7下的奇怪行为

Tomcat 8 (jvisualvm) 下的奇怪内存行为

相对元素下的绝对元素导致Firefox下的奇怪行为

在没有DBA权限的情况下更改不同数据库下多个模式的密码?

redis哨兵模式增加密码认证

VS2017 数据库项目在模式比较期间为用户生成错误的密码