From fe31cf5b83383cbc02f5bc31411367c0128f2df6 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Fri, 29 Jul 2016 15:50:30 +0200 Subject: Crypto: Use Hyper-V AES-NI detection workaround when displaying AES hardware availability in GUI. --- src/Common/Dlgcode.c | 5 ++- src/Crypto/Aes_hw_cpu.asm | 25 ++++++------ src/Crypto/cpu.c | 99 +++++++++++++++++++++++++++++++---------------- src/Volume/Cipher.cpp | 3 +- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index c9955714..1ecc3c0a 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -5517,12 +5517,13 @@ BOOL CALLBACK BenchmarkDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lP uint32 driverConfig = ReadDriverConfigurationFlags(); + int isAesHwSupported = is_aes_hw_cpu_supported(); - SetDlgItemTextW (hwndDlg, IDC_HW_AES, (wstring (L" ") + (GetString (is_aes_hw_cpu_supported() ? ((driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? "UISTR_DISABLED" : "UISTR_YES") : "NOT_APPLICABLE_OR_NOT_AVAILABLE"))).c_str()); + SetDlgItemTextW (hwndDlg, IDC_HW_AES, (wstring (L" ") + (GetString (isAesHwSupported ? ((driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? "UISTR_DISABLED" : "UISTR_YES") : "NOT_APPLICABLE_OR_NOT_AVAILABLE"))).c_str()); ToHyperlink (hwndDlg, IDC_HW_AES_LABEL_LINK); - if (is_aes_hw_cpu_supported() && (driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION)) + if (isAesHwSupported && (driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION)) { Warning ("DISABLED_HW_AES_AFFECTS_PERFORMANCE", hwndDlg); } diff --git a/src/Crypto/Aes_hw_cpu.asm b/src/Crypto/Aes_hw_cpu.asm index faaba4f3..edc20b29 100644 --- a/src/Crypto/Aes_hw_cpu.asm +++ b/src/Crypto/Aes_hw_cpu.asm @@ -286,17 +286,20 @@ ; byte is_aes_hw_cpu_supported (); - export_function is_aes_hw_cpu_supported - push %[R]bx - - mov eax, 1 - cpuid - mov eax, ecx - shr eax, 25 - and eax, 1 - - pop %[R]bx - ret +; We comment this since we have an alternative C implementation +; that supports Hyper-V detection workaround +; +; export_function is_aes_hw_cpu_supported +; push %[R]bx +; +; mov eax, 1 +; cpuid +; mov eax, ecx +; shr eax, 25 +; and eax, 1 +; +; pop %[R]bx +; ret ; void aes_hw_cpu_decrypt (const byte *ks, byte *data); diff --git a/src/Crypto/cpu.c b/src/Crypto/cpu.c index 53e5e686..5743e6fc 100644 --- a/src/Crypto/cpu.c +++ b/src/Crypto/cpu.c @@ -192,6 +192,47 @@ VC_INLINE int IsAMD(const uint32 output[4]) (output[3] /*EDX*/ == 0x444D4163); } +static int Detect_MS_HyperV_AES () +{ + int hasAesNI = 0; + // 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 cpuid[4]; + char HvProductName[13]; + + CpuId(0x40000000, cpuid); + memcpy (HvProductName, &cpuid[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); + 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 + } + + return hasAesNI; +} + void DetectX86Features() { uint32 cpuid[4], cpuid1[4]; @@ -215,40 +256,7 @@ void DetectX86Features() // 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 - } + g_hasAESNI = Detect_MS_HyperV_AES (); } #endif @@ -282,4 +290,27 @@ void DetectX86Features() *((volatile int*)&g_x86DetectionDone) = 1; } +int is_aes_hw_cpu_supported () +{ + int bHasAESNI = 0; + uint32 cpuid[4]; + + if (CpuId(1, cpuid)) + { + if (cpuid[2] & (1<<25)) + bHasAESNI = 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 (!bHasAESNI && (cpuid[2] & (1<<31))) + { + bHasAESNI = Detect_MS_HyperV_AES (); + } +#endif + } + + return bHasAESNI; +} + #endif + diff --git a/src/Volume/Cipher.cpp b/src/Volume/Cipher.cpp index 743ef34c..a90b3c46 100644 --- a/src/Volume/Cipher.cpp +++ b/src/Volume/Cipher.cpp @@ -19,6 +19,7 @@ #ifdef TC_AES_HW_CPU # include "Crypto/Aes_hw_cpu.h" +# include "Crypto/cpu.h" #endif namespace VeraCrypt @@ -181,7 +182,7 @@ namespace VeraCrypt if (!stateValid) { - state = is_aes_hw_cpu_supported() ? true : false; + state = g_hasAESNI ? true : false; stateValid = true; } return state && HwSupportEnabled; -- cgit v1.2.3