From a7be140f856b4619a3924e1be86595575a625521 Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Fri, 20 Apr 2018 17:11:07 +0200 Subject: [PATCH] Encrypt: use OpenSSL's EVP interface, which supports AES-NI without the need of another library --- src/Cedar/Server.c | 12 --- src/Cedar/Server.h | 1 - src/Mayaqua/Encrypt.c | 238 ++++++++++++++++++++++++------------------ src/Mayaqua/Encrypt.h | 8 -- src/Mayaqua/Mayaqua.h | 6 -- 5 files changed, 137 insertions(+), 128 deletions(-) diff --git a/src/Cedar/Server.c b/src/Cedar/Server.c index 1146b1c6..d4c2674f 100644 --- a/src/Cedar/Server.c +++ b/src/Cedar/Server.c @@ -5946,9 +5946,6 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f) // Disable the NAT-traversal feature s->DisableNatTraversal = CfgGetBool(f, "DisableNatTraversal"); - // Intel AES - s->DisableIntelAesAcceleration = CfgGetBool(f, "DisableIntelAesAcceleration"); - if (s->Cedar->Bridge == false) { // Enable the VPN-over-ICMP @@ -6372,9 +6369,6 @@ void SiWriteServerCfg(FOLDER *f, SERVER *s) CfgAddBool(f, "EnableVpnOverDns", s->EnableVpnOverDns); } - // Intel AES - CfgAddBool(f, "DisableIntelAesAcceleration", s->DisableIntelAesAcceleration); - if (c->Bridge == false) { OPENVPN_SSTP_CONFIG config; @@ -10982,12 +10976,6 @@ SERVER *SiNewServerEx(bool bridge, bool in_client_inner_server, bool relay_serve SetFifoCurrentReallocMemSize(MEM_FIFO_REALLOC_MEM_SIZE); - if (s->DisableIntelAesAcceleration) - { - // Disable the Intel AES acceleration - DisableIntelAesAccel(); - } - // Raise the priority if (s->NoHighPriorityProcess == false) { diff --git a/src/Cedar/Server.h b/src/Cedar/Server.h index 8b9b377b..86b8837d 100644 --- a/src/Cedar/Server.h +++ b/src/Cedar/Server.h @@ -293,7 +293,6 @@ struct SERVER bool DisableNatTraversal; // Disable the NAT-traversal feature bool EnableVpnOverIcmp; // VPN over ICMP is enabled bool EnableVpnOverDns; // VPN over DNS is enabled - bool DisableIntelAesAcceleration; // Disable the Intel AES acceleration bool NoMoreSave; // Do not save any more bool EnableConditionalAccept; // Apply the Conditional Accept the Listener bool EnableLegacySSL; // Enable Legacy SSL diff --git a/src/Mayaqua/Encrypt.c b/src/Mayaqua/Encrypt.c index 381d1c57..b8cf1974 100644 --- a/src/Mayaqua/Encrypt.c +++ b/src/Mayaqua/Encrypt.c @@ -145,9 +145,11 @@ #include #include -#ifdef USE_INTEL_AESNI_LIBRARY -#include -#endif // USE_INTEL_AESNI_LIBRARY +#ifdef _MSC_VER +#include // For __cpuid() +#else +#include // For __get_cpuid() +#endif LOCK *openssl_lock = NULL; @@ -156,7 +158,6 @@ int ssl_clientcert_index = 0; LOCK **ssl_lock_obj = NULL; UINT ssl_lock_num; static bool openssl_inited = false; -static bool is_intel_aes_supported = false; static unsigned char *Internal_SHA0(const unsigned char *d, size_t n, unsigned char *md); @@ -3662,7 +3663,6 @@ void InitCryptLibrary() { char tmp[16]; - CheckIfIntelAesNiSupportedInit(); // RAND_Init_For_SoftEther() openssl_lock = NewLock(); SSL_library_init(); @@ -4106,135 +4106,171 @@ void AesFreeKey(AES_KEY_VALUE *k) // AES encryption void AesEncrypt(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec) { - UCHAR ivec_copy[AES_IV_SIZE]; + EVP_CIPHER_CTX *ctx = NULL; + int dest_len = 0; + int len = 0; + int ret = 0; + // Validate arguments if (dest == NULL || src == NULL || size == 0 || k == NULL || ivec == NULL) { return; } -#ifdef USE_INTEL_AESNI_LIBRARY - if (is_intel_aes_supported) + // Create and initialize the context + ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) { - AesEncryptWithIntel(dest, src, size, k, ivec); + ERR_print_errors_fp(stderr); return; } -#endif // USE_INTEL_AESNI_LIBRARY - Copy(ivec_copy, ivec, AES_IV_SIZE); + // Disable padding, as it's handled by IkeEncryptWithPadding() + EVP_CIPHER_CTX_set_padding(ctx, false); - AES_cbc_encrypt(src, dest, size, k->EncryptKey, ivec, 1); + // Initialize the encryption operation + switch (k->KeySize) + { + case 16: + ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, k->KeyValue, ivec); + break; + + case 24: + ret = EVP_EncryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, k->KeyValue, ivec); + break; + + case 32: + ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, k->KeyValue, ivec); + break; + } + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + // Provide the message to be encrypted and obtain the cipher output + ret = EVP_EncryptUpdate(ctx, dest, &dest_len, src, size); + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + // Finalize the encryption + ret = EVP_EncryptFinal_ex(ctx, (unsigned char *) dest + dest_len, &len); + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + dest_len += len; + + // Clean up + EVP_CIPHER_CTX_free(ctx); } // AES decryption void AesDecrypt(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec) { - UCHAR ivec_copy[AES_IV_SIZE]; + EVP_CIPHER_CTX *ctx = NULL; + int dest_len = 0; + int len = 0; + int ret = 0; + // Validate arguments if (dest == NULL || src == NULL || size == 0 || k == NULL || ivec == NULL) { return; } -#ifdef USE_INTEL_AESNI_LIBRARY - if (is_intel_aes_supported) + // Create and initialize the context + ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) { - AesDecryptWithIntel(dest, src, size, k, ivec); + ERR_print_errors_fp(stderr); return; } -#endif // USE_INTEL_AESNI_LIBRARY - Copy(ivec_copy, ivec, AES_IV_SIZE); + // Disable padding, as it's handled by IkeEncryptWithPadding() + EVP_CIPHER_CTX_set_padding(ctx, false); - AES_cbc_encrypt(src, dest, size, k->DecryptKey, ivec, 0); + // Initialize the decryption operation + switch (k->KeySize) + { + case 16: + ret = EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, k->KeyValue, ivec); + break; + + case 24: + ret = EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, k->KeyValue, ivec); + break; + + case 32: + ret = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, k->KeyValue, ivec); + break; + } + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + // Provide the message to be decrypted and obtain the plaintext output + ret = EVP_DecryptUpdate(ctx, dest, &dest_len, src, size); + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + // Finalize the decryption + ret = EVP_DecryptFinal_ex(ctx, (unsigned char *) dest + dest_len, &len); + + if (ret != 1) + { + ERR_print_errors_fp(stderr); + EVP_CIPHER_CTX_free(ctx); + return; + } + + dest_len += len; + + // Clean up + EVP_CIPHER_CTX_free(ctx); } // Determine whether the Intel AES-NI is supported bool IsIntelAesNiSupported() { - return is_intel_aes_supported; + bool supported = false; + + // Unfortunately OpenSSL doesn't provide a function to do it +#ifdef _MSC_VER + int regs[4]; // EAX, EBX, ECX, EDX + __cpuid(regs, 1); + supported = (regs[2] >> 25) & 1; +#else + uint32_t eax, ebx, ecx, edx; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + supported = (ecx & bit_AES) > 0; +#endif + + return supported; } -void CheckIfIntelAesNiSupportedInit() -{ -#ifdef USE_INTEL_AESNI_LIBRARY - if (check_for_aes_instructions()) - { - is_intel_aes_supported = true; - } - else - { - is_intel_aes_supported = false; - } -#else // USE_INTEL_AESNI_LIBRARY - is_intel_aes_supported = false; -#endif // USE_INTEL_AESNI_LIBRARY -} - -// Disable the Intel AES-NI -void DisableIntelAesAccel() -{ - is_intel_aes_supported = false; -} - -#ifdef USE_INTEL_AESNI_LIBRARY -// Encrypt AES using the Intel AES-NI -void AesEncryptWithIntel(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec) -{ - UCHAR ivec_copy[AES_IV_SIZE]; - - // Validate arguments - if (dest == NULL || src == NULL || size == 0 || k == NULL || ivec == NULL) - { - return; - } - - Copy(ivec_copy, ivec, AES_IV_SIZE); - - switch (k->KeySize) - { - case 16: - intel_AES_enc128_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - - case 24: - intel_AES_enc192_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - - case 32: - intel_AES_enc256_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - } -} - -// Decrypt AES using the Intel AES-NI -void AesDecryptWithIntel(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec) -{ - UCHAR ivec_copy[AES_IV_SIZE]; - - // Validate arguments - if (dest == NULL || src == NULL || size == 0 || k == NULL || ivec == NULL) - { - return; - } - - Copy(ivec_copy, ivec, AES_IV_SIZE); - - switch (k->KeySize) - { - case 16: - intel_AES_dec128_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - - case 24: - intel_AES_dec192_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - - case 32: - intel_AES_dec256_CBC(src, dest, k->KeyValue, (size / AES_IV_SIZE), ivec_copy); - break; - } -} -#endif // USE_INTEL_AESNI_LIBRARY // Calculation of HMAC-SHA-1 void MacSha1(void *dst, void *key, UINT key_size, void *data, UINT data_size) diff --git a/src/Mayaqua/Encrypt.h b/src/Mayaqua/Encrypt.h index d795d2d6..10e0dd7b 100644 --- a/src/Mayaqua/Encrypt.h +++ b/src/Mayaqua/Encrypt.h @@ -523,12 +523,6 @@ void AesEncrypt(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec); void AesDecrypt(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec); bool IsIntelAesNiSupported(); -void CheckIfIntelAesNiSupportedInit(); - -#ifdef USE_INTEL_AESNI_LIBRARY -void AesEncryptWithIntel(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec); -void AesDecryptWithIntel(void *dest, void *src, UINT size, AES_KEY_VALUE *k, void *ivec); -#endif // USE_INTEL_AESNI_LIBRARY void OpenSSL_InitLock(); void OpenSSL_FreeLock(); @@ -551,8 +545,6 @@ void Enc_tls1_PRF(unsigned char *label, int label_len, const unsigned char *sec, void HMacSha1(void *dst, void *key, UINT key_size, void *data, UINT data_size); void HMacMd5(void *dst, void *key, UINT key_size, void *data, UINT data_size); -void DisableIntelAesAccel(); - int GetSslClientCertIndex(); #ifdef ENCRYPT_C diff --git a/src/Mayaqua/Mayaqua.h b/src/Mayaqua/Mayaqua.h index 400a0dab..290b69d8 100644 --- a/src/Mayaqua/Mayaqua.h +++ b/src/Mayaqua/Mayaqua.h @@ -215,12 +215,6 @@ int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow) #define PROBE_DATA(data, size) #endif // USE_PROBE -// About Intel AES-NI Library -#if (defined(OS_WIN32) || (defined(UNIX_LINUX) && (defined(CPU_X86) || defined(CPU_X64)))) -// Supports only for Linux (x86 / x64) or Windows -#define USE_INTEL_AESNI_LIBRARY -#endif - // Determine the performance / memory strategy #if (defined(CPU_X86) || defined(CPU_X64) || defined(CPU_X86_X64) || defined(CPU_SPARC) || defined(CPU_SPARC64) || defined(OS_WIN32) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__ia64__) || defined(__IA64__) || defined(_IA64)) #define USE_STRATEGY_PERFORMACE