From ea22c672d01824f7dc8ffb47b5dd26b548de5d20 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 23 May 2018 19:42:42 +0100 Subject: [PATCH] Only reuse CNG object if Windows 8+ --- src/openrct2/core/Hash.cpp | 124 ++++++++++++++--------- src/openrct2/platform/Platform.Win32.cpp | 28 ++--- src/openrct2/platform/Platform2.h | 4 + 3 files changed, 97 insertions(+), 59 deletions(-) diff --git a/src/openrct2/core/Hash.cpp b/src/openrct2/core/Hash.cpp index adefba0d61..7e4a0c0fa3 100644 --- a/src/openrct2/core/Hash.cpp +++ b/src/openrct2/core/Hash.cpp @@ -15,6 +15,7 @@ #pragma endregion #include "Hash.h" +#include "../platform/Platform2.h" #include #include @@ -40,6 +41,7 @@ private: BCRYPT_ALG_HANDLE _hAlg{}; BCRYPT_HASH_HANDLE _hHash{}; PBYTE _pbHashObject{}; + bool _reusable{}; #else EVP_MD_CTX * _ctx{}; #endif @@ -48,63 +50,30 @@ public: Sha1Algorithm() { #ifdef __USE_CNG__ - // TODO BCRYPT_HASH_REUSABLE_FLAG only available from Windows 8 - auto status = BCryptOpenAlgorithmProvider(&_hAlg, BCRYPT_SHA1_ALGORITHM, nullptr, BCRYPT_HASH_REUSABLE_FLAG); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptOpenAlgorithmProvider failed: " + std::to_string(status)); - } - - // Calculate the size of the buffer to hold the hash object - DWORD cbHashObject{}; - DWORD cbData{}; - status = BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptGetProperty failed: " + std::to_string(status)); - } - - // Create a hash - _pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject); - if (_pbHashObject == nullptr) - { - throw std::bad_alloc(); - } - status = BCryptCreateHash(_hAlg, &_hHash, _pbHashObject, cbHashObject, nullptr, 0, 0); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptCreateHash failed: " + std::to_string(status)); - } -#else - _ctx = EVP_MD_CTX_create(); - if (_ctx == nullptr) - { - throw std::runtime_error("EVP_MD_CTX_create failed"); - } - if (EVP_DigestInit_ex(_ctx, EVP_sha1(), nullptr) <= 0) - { - EVP_MD_CTX_destroy(_ctx); - throw std::runtime_error("EVP_DigestInit_ex failed"); - } + // BCRYPT_HASH_REUSABLE_FLAG only available from Windows 8 + _reusable = Platform::IsOSVersionAtLeast(6, 2, 0); #endif + Initialise(); } ~Sha1Algorithm() { -#ifdef __USE_CNG__ - BCryptCloseAlgorithmProvider(_hAlg, 0); - BCryptDestroyHash(_hHash); - HeapFree(GetProcessHeap(), 0, _pbHashObject); -#else - EVP_MD_CTX_destroy(_ctx); -#endif + Dispose(); } void Clear() override { #ifdef __USE_CNG__ - // Finishing the current digest clears the state ready for a new digest - Finish(); + if (_reusable) + { + // Finishing the current digest clears the state ready for a new digest + Finish(); + } + else + { + Dispose(); + Initialise(); + } #else if (EVP_DigestInit_ex(_ctx, EVP_sha1(), nullptr) <= 0) { @@ -154,6 +123,67 @@ public: return result; #endif } + +private: + void Initialise() + { +#ifdef __USE_CNG__ + auto flags = _reusable ? BCRYPT_HASH_REUSABLE_FLAG : 0; + auto status = BCryptOpenAlgorithmProvider(&_hAlg, BCRYPT_SHA1_ALGORITHM, nullptr, flags); + if (!NT_SUCCESS(status)) + { + throw std::runtime_error("BCryptOpenAlgorithmProvider failed: " + std::to_string(status)); + } + + // Calculate the size of the buffer to hold the hash object + DWORD cbHashObject{}; + DWORD cbData{}; + status = BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0); + if (!NT_SUCCESS(status)) + { + throw std::runtime_error("BCryptGetProperty failed: " + std::to_string(status)); + } + + // Create a hash + _pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject); + if (_pbHashObject == nullptr) + { + throw std::bad_alloc(); + } + status = BCryptCreateHash(_hAlg, &_hHash, _pbHashObject, cbHashObject, nullptr, 0, 0); + if (!NT_SUCCESS(status)) + { + throw std::runtime_error("BCryptCreateHash failed: " + std::to_string(status)); + } +#else + _ctx = EVP_MD_CTX_create(); + if (_ctx == nullptr) + { + throw std::runtime_error("EVP_MD_CTX_create failed"); + } + if (EVP_DigestInit_ex(_ctx, EVP_sha1(), nullptr) <= 0) + { + EVP_MD_CTX_destroy(_ctx); + throw std::runtime_error("EVP_DigestInit_ex failed"); + } +#endif + } + + void Dispose() + { +#ifdef __USE_CNG__ + BCryptCloseAlgorithmProvider(_hAlg, 0); + BCryptDestroyHash(_hHash); + HeapFree(GetProcessHeap(), 0, _pbHashObject); + + _hAlg = {}; + _hHash = {}; + _pbHashObject = {}; +#else + EVP_MD_CTX_destroy(_ctx); + _ctx = {}; +#endif + } }; namespace Hash diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index e8334eab58..8604aa1b55 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -197,15 +197,10 @@ namespace Platform return result; } - /** - * Checks if the current version of Windows supports ANSI colour codes. - * From Windows 10, build 10586 ANSI escape colour codes can be used on stdout. - */ - static bool HasANSIColourSupport() + bool IsOSVersionAtLeast(uint32 major, uint32 minor, uint32 build) { - const DWORD MINV_MAJOR = 10, MINV_MINOR = 0, MINV_BUILD = 10586; bool result = false; - HMODULE hModule = GetModuleHandleA("ntdll.dll"); + auto hModule = GetModuleHandleA("ntdll.dll"); if (hModule != nullptr) { using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW); @@ -216,11 +211,11 @@ namespace Platform rovi.dwOSVersionInfoSize = sizeof(rovi); if (fn(&rovi) == 0) { - if (rovi.dwMajorVersion > MINV_MAJOR || - (rovi.dwMajorVersion == MINV_MAJOR && - (rovi.dwMinorVersion > MINV_MINOR || - (rovi.dwMinorVersion == MINV_MINOR && - rovi.dwBuildNumber >= MINV_BUILD)))) + if (rovi.dwMajorVersion > major || + (rovi.dwMajorVersion == major && + (rovi.dwMinorVersion > minor || + (rovi.dwMinorVersion == minor && + rovi.dwBuildNumber >= build)))) { result = true; } @@ -230,6 +225,15 @@ namespace Platform return result; } + /** + * Checks if the current version of Windows supports ANSI colour codes. + * From Windows 10, build 10586 ANSI escape colour codes can be used on stdout. + */ + static bool HasANSIColourSupport() + { + return IsOSVersionAtLeast(10, 0, 10586); + } + static void EnableANSIConsole() { if (HasANSIColourSupport()) diff --git a/src/openrct2/platform/Platform2.h b/src/openrct2/platform/Platform2.h index b130580b6b..44d60d9dfe 100644 --- a/src/openrct2/platform/Platform2.h +++ b/src/openrct2/platform/Platform2.h @@ -45,5 +45,9 @@ namespace Platform std::string FormatShortDate(std::time_t timestamp); std::string FormatTime(std::time_t timestamp); +#ifdef _WIN32 + bool IsOSVersionAtLeast(uint32 major, uint32 minor, uint32 build); +#endif + bool IsColourTerminalSupported(); } // namespace Platform