使用 VS2017 在发布模式下 Crypto++ AES 崩溃

Crypto++ AES crashing in release mode using VS2017

我有以下代码。一个非常简单的字符串"abcd"加密解密的例子。我已经用 Crypto++ (https://www.cryptopp.com/wiki/CBC_mode) 中的示例进行了尝试,它产生了相同的异常。

AutoSeededRandomPool rand;

SecByteBlock key(nullptr, AES::MAX_KEYLENGTH);
rand.GenerateBlock(key, key.size());

byte iv[AES::BLOCKSIZE];
rand.GenerateBlock(iv, AES::BLOCKSIZE);

std::string encryptedData;
CBC_Mode<AES>::Encryption cbcEncryption(key, key.size(), iv);

StringSource ss("abcd", true,
    new StreamTransformationFilter(cbcEncryption,
        new StringSink(encryptedData)
    )
);

std::string decryptedData;

CBC_Mode<AES>::Decryption cbcDecryption(key, key.size(), iv);

StringSource ss2(encryptedData, true,
    new StreamTransformationFilter(cbcDecryption,
        new StringSink(decryptedData)
    )
);

问题是当我在调试模式下构建时,它工作正常但是当我在发布模式下构建时,我从 Crypto++ 代码中得到一个异常 ("StreamTransformationFilter: invalid PKCS #7 block padding found")

The problem is when I build in debug mode, it works fine but when I do it in release mode I get an exception from Crypto++ code ("StreamTransformationFilter: invalid PKCS #7 block padding found") ...

这似乎是与全局优化相关的编译器问题。我们的解决方法是禁用源文件 rijndael.cpp.

的全局优化

rijndael.cpp 中,您可以在文件顶部添加以下内容以避免出现此问题:

#if defined(_MSC_VER) && (_MSC_VER >= 1910)
# pragma optimize("", off)
# pragma optimize("ts", on)
#endif

您可以在 rijndael.cpp 中使用以下方法重现该问题:

#if defined(_MSC_VER) && (_MSC_VER >= 1910)
# pragma optimize("", off)
# pragma optimize("g", on)
#endif

另请参阅 MSDN 上的 Commit f57df06c5e6d and pragma optimize


如果您的机器有 AES-NI 但您想重现该问题,请注释掉 cpu.cpp 中分配 g_hasAESNI 的代码。 g_hasAESNI 将保留默认值 false

--- a/cpu.cpp
+++ b/cpu.cpp
@@ -242,7 +242,7 @@ void DetectX86Features()
        g_hasSSSE3 = g_hasSSE2 && ((cpuid1[2] & (1<< 9)) != 0);
        g_hasSSE41 = g_hasSSE2 && ((cpuid1[2] & (1<<19)) != 0);
        g_hasSSE42 = g_hasSSE2 && ((cpuid1[2] & (1<<20)) != 0);
-       g_hasAESNI = g_hasSSE2 && ((cpuid1[2] & (1<<25)) != 0);
+       //g_hasAESNI = g_hasSSE2 && ((cpuid1[2] & (1<<25)) != 0);
        g_hasCLMUL = g_hasSSE2 && ((cpuid1[2] & (1<< 1)) != 0);