From 3b2b15c0f3be42741a88f416c0085746657196a4 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 26 May 2018 00:11:01 +0100 Subject: [PATCH] Implement CNG implementation bar pem reading --- openrct2.common.props | 2 +- src/openrct2/core/Crypt.CNG.cpp | 152 +++++++++++++++++++++++----- src/openrct2/core/Crypt.OpenSSL.cpp | 1 - src/openrct2/core/Crypt.h | 7 ++ 4 files changed, 134 insertions(+), 28 deletions(-) diff --git a/openrct2.common.props b/openrct2.common.props index 3b41540661..c89aaf6339 100644 --- a/openrct2.common.props +++ b/openrct2.common.props @@ -61,7 +61,7 @@ /utf-8 /std:c++latest /permissive- /Zc:externConstexpr - imm32.lib;version.lib;winmm.lib;crypt32.lib;wldap32.lib;bcrypt.lib;%(AdditionalDependencies) + imm32.lib;version.lib;winmm.lib;crypt32.lib;wldap32.lib;bcrypt.lib;ncrypt.lib;%(AdditionalDependencies) /OPT:NOLBR /ignore:4099 %(AdditionalOptions) diff --git a/src/openrct2/core/Crypt.CNG.cpp b/src/openrct2/core/Crypt.CNG.cpp index 20b6a7ff22..fa7f9786cb 100644 --- a/src/openrct2/core/Crypt.CNG.cpp +++ b/src/openrct2/core/Crypt.CNG.cpp @@ -18,22 +18,38 @@ #define __USE_CNG__ #endif -#undef __USE_CNG__ - #ifdef __USE_CNG__ #include "Crypt.h" #include "../platform/Platform2.h" #include #include +#include // CNG: Cryptography API: Next Generation (CNG) // available in Windows Vista onwards. #define WIN32_LEAN_AND_MEAN #include #include +#include #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +static void CngThrowOnBadStatus(const std::string_view& name, NTSTATUS status) +{ + if (!NT_SUCCESS(status)) + { + throw std::runtime_error(std::string(name) + " failed: " + std::to_string(status)); + } +} + +static void ThrowBadAllocOnNull(const void * ptr) +{ + if (ptr == nullptr) + { + throw std::bad_alloc(); + } +} + template class CngHashAlgorithm final : public TBase { @@ -76,10 +92,7 @@ public: TBase * Update(const void * data, size_t dataLen) override { auto status = BCryptHashData(_hHash, (PBYTE)data, (ULONG)dataLen, 0); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptHashData failed: " + std::to_string(status)); - } + CngThrowOnBadStatus("BCryptHashData", status); return this; } @@ -87,10 +100,7 @@ public: { typename TBase::Result result; auto status = BCryptFinishHash(_hHash, result.data(), (ULONG)result.size(), 0); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptFinishHash failed: " + std::to_string(status)); - } + CngThrowOnBadStatus("BCryptFinishHash", status); return result; } @@ -99,31 +109,19 @@ private: { auto flags = _reusable ? BCRYPT_HASH_REUSABLE_FLAG : 0; auto status = BCryptOpenAlgorithmProvider(&_hAlg, _algName, nullptr, flags); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptOpenAlgorithmProvider failed: " + std::to_string(status)); - } + CngThrowOnBadStatus("BCryptOpenAlgorithmProvider", 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)); - } + CngThrowOnBadStatus("BCryptGetProperty", status); // Create a hash _pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject); - if (_pbHashObject == nullptr) - { - throw std::bad_alloc(); - } + ThrowBadAllocOnNull(_pbHashObject); status = BCryptCreateHash(_hAlg, &_hHash, _pbHashObject, cbHashObject, nullptr, 0, 0); - if (!NT_SUCCESS(status)) - { - throw std::runtime_error("BCryptCreateHash failed: " + std::to_string(status)); - } + CngThrowOnBadStatus("BCryptCreateHash", status); } void Dispose() @@ -138,6 +136,98 @@ private: } }; +class CngRsaKey final : public RsaKey +{ +public: + NCRYPT_KEY_HANDLE GetKeyHandle() const { return _hKey; } + + void SetPrivate(const std::string_view& pem) override + { + SetKey(pem, true); + } + + void SetPublic(const std::string_view& pem) override + { + SetKey(pem, false); + } + + std::string GetPrivate() override { return GetKey(true); } + + std::string GetPublic() override { return GetKey(false); } + +private: + NCRYPT_KEY_HANDLE _hKey{}; + + void SetKey(const std::string_view& pem, bool isPrivate) + { + throw std::runtime_error("Not implemented"); + } + + std::string GetKey(bool isPrivate) + { + throw std::runtime_error("Not implemented"); + } +}; + +class CngRsaAlgorithm final : public RsaAlgorithm +{ +public: + std::vector SignData(const RsaKey& key, const void * data, size_t dataLen) override + { + auto hKey = static_cast(key).GetKeyHandle(); + auto [cbHash, pbHash] = HashData(data, dataLen); + auto [cbSignature, pbSignature] = std::tuple(); + try + { + BCRYPT_PKCS1_PADDING_INFO paddingInfo{ BCRYPT_SHA256_ALGORITHM }; + auto status = NCryptSignHash(hKey, &paddingInfo, pbHash, cbHash, NULL, 0, &cbSignature, BCRYPT_PAD_PKCS1); + CngThrowOnBadStatus("NCryptSignHash", status); + pbSignature = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbSignature); + ThrowBadAllocOnNull(pbSignature); + status = NCryptSignHash(hKey, &paddingInfo, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, BCRYPT_PAD_PKCS1); + CngThrowOnBadStatus("NCryptSignHash", status); + + auto result = std::vector(pbSignature, pbSignature + cbSignature); + HeapFree(GetProcessHeap(), 0, pbSignature); + return result; + } + catch (std::exception&) + { + HeapFree(GetProcessHeap(), 0, pbHash); + HeapFree(GetProcessHeap(), 0, pbSignature); + throw; + } + } + + bool VerifyData(const RsaKey& key, const void * data, size_t dataLen, const void * sig, size_t sigLen) override + { + auto hKey = static_cast(key).GetKeyHandle(); + auto [cbHash, pbHash] = HashData(data, dataLen); + auto [cbSignature, pbSignature] = ToHeap(sig, sigLen); + + BCRYPT_PKCS1_PADDING_INFO paddingInfo { BCRYPT_SHA256_ALGORITHM }; + auto status = NCryptVerifySignature(hKey, &paddingInfo, pbHash, cbHash, pbSignature, cbSignature, BCRYPT_PAD_PKCS1); + HeapFree(GetProcessHeap(), 0, pbSignature); + return status == ERROR_SUCCESS; + } + +private: + static std::tuple HashData(const void * data, size_t dataLen) + { + auto hash = Hash::SHA256(data, dataLen); + return ToHeap(hash.data(), hash.size()); + } + + static std::tuple ToHeap(const void * data, size_t dataLen) + { + auto cbHash = (DWORD)dataLen; + auto pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, dataLen); + ThrowBadAllocOnNull(pbHash); + std::memcpy(pbHash, data, dataLen); + return std::make_tuple(cbHash, pbHash); + } +}; + namespace Hash { std::unique_ptr CreateSHA1() @@ -149,6 +239,16 @@ namespace Hash { return std::make_unique>(BCRYPT_SHA256_ALGORITHM); } + + std::unique_ptr CreateRSA() + { + return std::make_unique(); + } + + std::unique_ptr CreateRSAKey() + { + return std::make_unique(); + } } #endif diff --git a/src/openrct2/core/Crypt.OpenSSL.cpp b/src/openrct2/core/Crypt.OpenSSL.cpp index be59c08cf2..9561a3c393 100644 --- a/src/openrct2/core/Crypt.OpenSSL.cpp +++ b/src/openrct2/core/Crypt.OpenSSL.cpp @@ -18,7 +18,6 @@ #define __USE_CNG__ #endif -#undef __USE_CNG__ #ifndef __USE_CNG__ #include "Crypt.h" diff --git a/src/openrct2/core/Crypt.h b/src/openrct2/core/Crypt.h index e2c2ed6e21..029442fedf 100644 --- a/src/openrct2/core/Crypt.h +++ b/src/openrct2/core/Crypt.h @@ -66,4 +66,11 @@ namespace Hash ->Update(data, dataLen) ->Finish(); } + + inline Sha256Algorithm::Result SHA256(const void * data, size_t dataLen) + { + return CreateSHA256() + ->Update(data, dataLen) + ->Finish(); + } }