Crypto: Workaround for AES-NI issue under Hyper-V on Windows Server 2008 R2 which masks AES-NI from applications although it is available.

This commit is contained in:
Mounir IDRASSI 2016-07-24 23:39:33 +02:00
parent 2dbf366184
commit 0fca588275
No known key found for this signature in database
GPG Key ID: DD0C382D5FCFB8FC
3 changed files with 66 additions and 3 deletions

View File

@ -21,6 +21,7 @@
#include "EncryptionThreadPool.h" #include "EncryptionThreadPool.h"
#endif #endif
#include "Volumes.h" #include "Volumes.h"
#include "cpu.h"
/* Update the following when adding a new cipher or EA: /* Update the following when adding a new cipher or EA:
@ -1051,7 +1052,11 @@ BOOL IsAesHwCpuSupported ()
if (!stateValid) if (!stateValid)
{ {
#ifdef TC_WINDOWS_BOOT_AES
state = is_aes_hw_cpu_supported() ? TRUE : FALSE; state = is_aes_hw_cpu_supported() ? TRUE : FALSE;
#else
state = g_hasAESNI ? TRUE : FALSE;
#endif
stateValid = TRUE; stateValid = TRUE;
} }

View File

@ -118,20 +118,32 @@ static int TrySSE2()
#if CRYPTOPP_BOOL_X64 #if CRYPTOPP_BOOL_X64
return 1; return 1;
#elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY) #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
volatile int result = 1;
#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
KFLOATING_SAVE floatingPointState;
if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)))
{
#endif
__try __try
{ {
#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
AS2(por xmm0, xmm0) // executing SSE2 instruction AS2(por xmm0, xmm0) // executing SSE2 instruction
#elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
__m128i x = _mm_setzero_si128(); __m128i x = _mm_setzero_si128();
return _mm_cvtsi128_si32(x) == 0 ? 1 : 0; result = _mm_cvtsi128_si32(x) == 0 ? 1 : 0;
#endif #endif
} }
__except (EXCEPTION_EXECUTE_HANDLER) __except (EXCEPTION_EXECUTE_HANDLER)
{ {
return 0; result = 0;
} }
return 1; #if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
KeRestoreFloatingPointState (&floatingPointState);
}
else
return 0;
#endif
return result;
#else #else
// longjmp and clobber warnings. Volatile is required. // longjmp and clobber warnings. Volatile is required.
// http://github.com/weidai11/cryptopp/issues/24 // http://github.com/weidai11/cryptopp/issues/24
@ -198,6 +210,48 @@ void DetectX86Features()
g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25)); g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1)); g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
#if (defined(__AES__) && defined(__PCLMUL__)) || defined(__INTEL_COMPILER) || CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
// Hypervisor = bit 31 of ECX of CPUID leaf 0x1
// reference: http://artemonsecurity.com/vmde.pdf
if (!g_hasAESNI && (cpuid1[2] & (1<<31)))
{
// when Hyper-V is enabled on older versions of Windows Server (i.e. 2008 R2), the AES-NI capability
// gets masked out for all applications, even running on the host.
// We try to detect Hyper-V virtual CPU and perform a dummy AES-NI operation to check its real presence
uint32 cpuid2[4];
char HvProductName[13];
CpuId(0x40000000, cpuid2);
memcpy (HvProductName, &cpuid2[1], 12);
HvProductName[12] = 0;
if (_stricmp(HvProductName, "Microsoft Hv") == 0)
{
#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
KFLOATING_SAVE floatingPointState;
if (NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)))
{
#endif
__try
{
__m128i block, subkey, ciphered;
// perform AES round.
block = _mm_setr_epi32(0x11223344,0x55667788,0x99AABBCC,0xDDEEFF00);
subkey = _mm_setr_epi32(0xA5A5A5A5,0xA5A5A5A5,0x5A5A5A5A,0x5A5A5A5A);
ciphered = _mm_aesenc_si128(block, subkey);
g_hasAESNI = (ciphered.m128i_u64[0] == LL(0x2f4654b9485061fa) && ciphered.m128i_u64[1] == LL(0xc8b51f1fe1256f99));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
// ignore error if AES-NI not supported
}
#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
KeRestoreFloatingPointState (&floatingPointState);
}
#endif
}
}
#endif
if ((cpuid1[3] & (1 << 25)) != 0) if ((cpuid1[3] & (1 << 25)) != 0)
g_hasISSE = 1; g_hasISSE = 1;
else else

View File

@ -3,6 +3,10 @@
#include "config.h" #include "config.h"
#include <string.h> // for memcpy and memmove #include <string.h> // for memcpy and memmove
#ifndef _WIN32
#include <strings.h> // for strcasecmp
#define _stricmp strcasecmp
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
#if _MSC_VER >= 1400 #if _MSC_VER >= 1400