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();
+ }
}