C++ 进行编译加密++;使用AES/GCM加密的库代码利用英特尔&x27;s-NI指令?

C++ 进行编译加密++;使用AES/GCM加密的库代码利用英特尔&x27;s-NI指令?,c++,aes,crypto++,aes-gcm,aes-ni,C++,Aes,Crypto++,Aes Gcm,Aes Ni,我正在使用Crypto++库实现和验证。我的代码是使用Visual Studio 2008作为C++/MFC项目编译的。这是一个稍旧的项目,它使用了库的早期版本,Cryptopp562 我很好奇编译后的代码是否会使用英特尔的?如果是这样,如果硬件(旧的CPU)不支持它会发生什么 编辑:下面是我正在测试的代码示例: int nIV_长度=12; int nAES_KeyLength=32; 字节*iv=新字节[nIV_长度]; 字节*键=新字节[nAES_键长度]; int nLnPlainTex

我正在使用Crypto++库实现和验证。我的代码是使用Visual Studio 2008作为C++/MFC项目编译的。这是一个稍旧的项目,它使用了库的早期版本,
Cryptopp562

我很好奇编译后的代码是否会使用英特尔的?如果是这样,如果硬件(旧的CPU)不支持它会发生什么

编辑:下面是我正在测试的代码示例:

int nIV_长度=12;
int nAES_KeyLength=32;
字节*iv=新字节[nIV_长度];
字节*键=新字节[nAES_键长度];
int nLnPlainText=128;
BYTE*pDataPlainText=新字节[nLnPlainText];
CryptoPP::AutoSeedRandomPool rng;
发电机锁(iv,nIV_长度);
CryptoPP::GCM::加密enc;
enc.SetKeyWithIV(键、nAES_键长度、iv、nIV_长度);
BYTE*pDataOut_AES_GCM=新字节[nLnPlainText];
memset(pDataOut\u AES\u GCM,0,nLnPlainText);
字节mac[16]={0};
enc.EncryptAndAuthenticate(pDataOut_AES_GCM,mac,sizeof(mac),iv,nIV_长度,NULL,0,pDataPlainText,NLNPlaintText);
删除明文;
删除[]pDataOut_AES_GCM;
删除[]键;
删除[]四;

如果在不支持AES-NI指令的x86硬件上运行包含AES-NI指令的代码,则会出现无效指令错误。除非代码做了一些聪明的事情(例如查看CPUID以决定是否运行AES-NI优化代码或其他事情),否则这也可以用于检测是否实际使用了AES-NI指令

否则,您可以始终使用调试器,并在AES-NI指令处设置断点,以查看您的进程是否使用过该部分代码


根据AES,5.6.1版中添加了NI支持。查看5.6.5 Crypto++版本的源代码,如果在编译时启用了AES-NI支持,那么它将使用运行时检查(可能使用CPUID的
hasasni()
函数)来决定是否使用这些内部函数。有关详细信息,请参阅其源代码中的(和CPUID代码)。

如果在不支持这些指令的x86硬件上运行包含AES-NI指令的代码,则会出现无效指令错误。除非代码做了一些聪明的事情(例如查看CPUID以决定是否运行AES-NI优化代码或其他事情),否则这也可以用于检测是否实际使用了AES-NI指令

否则,您可以始终使用调试器,并在AES-NI指令处设置断点,以查看您的进程是否使用过该部分代码

根据AES,5.6.1版中添加了NI支持。查看5.6.5 Crypto++版本的源代码,如果在编译时启用了AES-NI支持,那么它将使用运行时检查(可能使用CPUID的
hasasni()
函数)来决定是否使用这些内部函数。有关详细信息,请参阅其源代码中的(和,获取CPUID代码)

我很好奇生成的编译代码是否会使用Intel的AES-NI指令

Crypto++5.6.1增加了对GCM下AES-NI和Carryless乘法的支持。当满足两个或三个条件时使用。首先,您使用的是具有支持的库版本。从新闻下的主页(或自述文件):

  • 2010年8月9日-5.6.1版发布

    • 在AES和GMAC/GCM中增加了对AES-NI和CLMUL指令集的支持
其次,编译器、汇编器和链接器必须支持这些指令。对于Crypto++,这意味着您至少要使用MSVC 2008 SP1、GCC 4.3和Binutils 2.19。对于MSVC,如果你看一下,它的防护措施如下(
\uuuuu AES\uuuuu
也适用于GCC和朋友):

您可以在以下位置查找数字:。讽刺的是,我从未在MSDN上看到过类似的页面,即使服务包很重要。你必须去一个中文网站。例如,VS2005SP1(IIRC)中出现了检查迭代器

对于Linux和GCC兼容,检查编译器和汇编程序的版本。如果它们太旧,则makefile会将
CRYPTOPP\u DISABLE\u AESNI
添加到命令行,以禁用支持,即使定义了
\u AES\u

CRYPTOPP\u DISABLE\u AESNI
出现的频率比您想象的要高。例如,如果下载OpenBSD6.0(当前版本),则
CRYPTOPP\u DISABLE\u AESNI将出现,因为它们的汇编程序太旧了。他们大多停留在GPL-2之前版本的工具上(显然他们不同意许可证的更改)

第三,CPU支持AES和SSE4指令(SSE4指令的原因如下所述)。这些检查在运行时执行,感兴趣的函数称为
HasAES()
from(还有一个
hasse4()
):

第(3)项的警告是需要在第(2)项的支持下编译库。如果项(2)不包括编译时支持,则项(3)不能提供运行时支持

关于第(3)项和运行时支持,我们最近不得不对其进行调优。一些低端Atom处理器,如D2500,似乎有SSE2、SSE3、SSSE3和AES-NI,但没有SSE4.1或SSE4.2。根据Intel ARK,它是处理器的可选配置。我们收到一个关于AES-NI代码路径中非法SSE4指令的错误报告,因此我们必须添加一个
hasse4()
检查。看


如果是这样,如果硬件(旧的CPU)不支持它会发生什么

没什么。使用默认的CXX实现,而不是硬件加速的AES

您可能有兴趣知道我们还有其他AES硬件加速,包括ARMv8加密和VIA挂锁。我们还提供其他硬件加速,如CRC32、无卡利乘法器和SHA。它们的功能都是一样的——编译时支持是跨语言的
int nIV_Length = 12;
int nAES_KeyLength = 32;
BYTE* iv = new BYTE[nIV_Length];
BYTE* key = new BYTE[nAES_KeyLength];

int nLnPlainText = 128;
BYTE* pDataPlainText = new BYTE[nLnPlainText];

CryptoPP::AutoSeededRandomPool rng;
rng.GenerateBlock(iv, nIV_Length);

CryptoPP::GCM<CryptoPP::AES>::Encryption enc;
enc.SetKeyWithIV(key, nAES_KeyLength, iv, nIV_Length);

BYTE* pDataOut_AES_GCM = new BYTE[nLnPlainText];
memset(pDataOut_AES_GCM, 0, nLnPlainText);

BYTE mac[16] = {0};
enc.EncryptAndAuthenticate(pDataOut_AES_GCM, mac, sizeof(mac), iv, nIV_Length, NULL, 0, pDataPlainText, nLnPlainText);

delete[] pDataPlainText;
delete[] pDataOut_AES_GCM;
delete[] key;
delete[] iv;
#if ... (_MSC_FULL_VER >= 150030729) ...
    #define CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE 1
#else
    #define CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE 0
#endif
//! \brief Determines AES-NI availability
//! \returns true if AES-NI is determined to be available, false otherwise
//! \details HasAESNI() is a runtime check performed using CPUID
inline bool HasAESNI()
{
    if (!g_x86DetectionDone)
        DetectX86Features();
    return g_hasAESNI;
}
size_t Rijndael::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
{
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
    if (HasAESNI())
        return AESNI_AdvancedProcessBlocks(AESNI_Enc_Block, AESNI_Enc_4_Blocks, (MAYBE_CONST __m128i *)(const void *)m_key.begin(), m_rounds, inBlocks, xorBlocks, outBlocks, length, flags);
#endif
int nCntTest = 100000;
DWORD dwmsIniTicks = ::GetTickCount();

for(int i = 0; i < nCntTest; i++)
{
    enc.EncryptAndAuthenticate(pDataOut_AES_GCM, mac, sizeof(mac), iv, nIV_Length, NULL, 0, pDataPlainText, nLnPlainText);
}

DWORD dwmsElapsed = ::GetTickCount() - dwmsIniTicks;

bool bHaveHwAES_Support = false;
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
bHaveHwAES_Support = CryptoPP::HasAESNI();
#endif
_tprintf(L"\nTimed %d AES256-GCM encryptions %s hardware encryption of %d bytes: %u ms\n", 
    nCntTest, bHaveHwAES_Support ? L"with" : L"without", 
    nLnRealPlainText, dwmsElapsed);