mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement CNG implementation bar pem reading
This commit is contained in:
parent
9e214258c3
commit
3b2b15c0f3
|
@ -61,7 +61,7 @@
|
||||||
<AdditionalOptions>/utf-8 /std:c++latest /permissive- /Zc:externConstexpr</AdditionalOptions>
|
<AdditionalOptions>/utf-8 /std:c++latest /permissive- /Zc:externConstexpr</AdditionalOptions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>imm32.lib;version.lib;winmm.lib;crypt32.lib;wldap32.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>imm32.lib;version.lib;winmm.lib;crypt32.lib;wldap32.lib;bcrypt.lib;ncrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<AdditionalOptions>/OPT:NOLBR /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
|
<AdditionalOptions>/OPT:NOLBR /ignore:4099 %(AdditionalOptions)</AdditionalOptions>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
|
@ -18,22 +18,38 @@
|
||||||
#define __USE_CNG__
|
#define __USE_CNG__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef __USE_CNG__
|
|
||||||
|
|
||||||
#ifdef __USE_CNG__
|
#ifdef __USE_CNG__
|
||||||
|
|
||||||
#include "Crypt.h"
|
#include "Crypt.h"
|
||||||
#include "../platform/Platform2.h"
|
#include "../platform/Platform2.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
// CNG: Cryptography API: Next Generation (CNG)
|
// CNG: Cryptography API: Next Generation (CNG)
|
||||||
// available in Windows Vista onwards.
|
// available in Windows Vista onwards.
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <bcrypt.h>
|
#include <bcrypt.h>
|
||||||
|
#include <ncrypt.h>
|
||||||
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
#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<typename TBase>
|
template<typename TBase>
|
||||||
class CngHashAlgorithm final : public TBase
|
class CngHashAlgorithm final : public TBase
|
||||||
{
|
{
|
||||||
|
@ -76,10 +92,7 @@ public:
|
||||||
TBase * Update(const void * data, size_t dataLen) override
|
TBase * Update(const void * data, size_t dataLen) override
|
||||||
{
|
{
|
||||||
auto status = BCryptHashData(_hHash, (PBYTE)data, (ULONG)dataLen, 0);
|
auto status = BCryptHashData(_hHash, (PBYTE)data, (ULONG)dataLen, 0);
|
||||||
if (!NT_SUCCESS(status))
|
CngThrowOnBadStatus("BCryptHashData", status);
|
||||||
{
|
|
||||||
throw std::runtime_error("BCryptHashData failed: " + std::to_string(status));
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +100,7 @@ public:
|
||||||
{
|
{
|
||||||
typename TBase::Result result;
|
typename TBase::Result result;
|
||||||
auto status = BCryptFinishHash(_hHash, result.data(), (ULONG)result.size(), 0);
|
auto status = BCryptFinishHash(_hHash, result.data(), (ULONG)result.size(), 0);
|
||||||
if (!NT_SUCCESS(status))
|
CngThrowOnBadStatus("BCryptFinishHash", status);
|
||||||
{
|
|
||||||
throw std::runtime_error("BCryptFinishHash failed: " + std::to_string(status));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,31 +109,19 @@ private:
|
||||||
{
|
{
|
||||||
auto flags = _reusable ? BCRYPT_HASH_REUSABLE_FLAG : 0;
|
auto flags = _reusable ? BCRYPT_HASH_REUSABLE_FLAG : 0;
|
||||||
auto status = BCryptOpenAlgorithmProvider(&_hAlg, _algName, nullptr, flags);
|
auto status = BCryptOpenAlgorithmProvider(&_hAlg, _algName, nullptr, flags);
|
||||||
if (!NT_SUCCESS(status))
|
CngThrowOnBadStatus("BCryptOpenAlgorithmProvider", status);
|
||||||
{
|
|
||||||
throw std::runtime_error("BCryptOpenAlgorithmProvider failed: " + std::to_string(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the size of the buffer to hold the hash object
|
// Calculate the size of the buffer to hold the hash object
|
||||||
DWORD cbHashObject{};
|
DWORD cbHashObject{};
|
||||||
DWORD cbData{};
|
DWORD cbData{};
|
||||||
status = BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
|
status = BCryptGetProperty(_hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
|
||||||
if (!NT_SUCCESS(status))
|
CngThrowOnBadStatus("BCryptGetProperty", status);
|
||||||
{
|
|
||||||
throw std::runtime_error("BCryptGetProperty failed: " + std::to_string(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a hash
|
// Create a hash
|
||||||
_pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
|
_pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
|
||||||
if (_pbHashObject == nullptr)
|
ThrowBadAllocOnNull(_pbHashObject);
|
||||||
{
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
status = BCryptCreateHash(_hAlg, &_hHash, _pbHashObject, cbHashObject, nullptr, 0, 0);
|
status = BCryptCreateHash(_hAlg, &_hHash, _pbHashObject, cbHashObject, nullptr, 0, 0);
|
||||||
if (!NT_SUCCESS(status))
|
CngThrowOnBadStatus("BCryptCreateHash", status);
|
||||||
{
|
|
||||||
throw std::runtime_error("BCryptCreateHash failed: " + std::to_string(status));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dispose()
|
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<uint8_t> SignData(const RsaKey& key, const void * data, size_t dataLen) override
|
||||||
|
{
|
||||||
|
auto hKey = static_cast<const CngRsaKey&>(key).GetKeyHandle();
|
||||||
|
auto [cbHash, pbHash] = HashData(data, dataLen);
|
||||||
|
auto [cbSignature, pbSignature] = std::tuple<DWORD, PBYTE>();
|
||||||
|
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<uint8_t>(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<const CngRsaKey&>(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<DWORD, PBYTE> HashData(const void * data, size_t dataLen)
|
||||||
|
{
|
||||||
|
auto hash = Hash::SHA256(data, dataLen);
|
||||||
|
return ToHeap(hash.data(), hash.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::tuple<DWORD, PBYTE> 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
|
namespace Hash
|
||||||
{
|
{
|
||||||
std::unique_ptr<Sha1Algorithm> CreateSHA1()
|
std::unique_ptr<Sha1Algorithm> CreateSHA1()
|
||||||
|
@ -149,6 +239,16 @@ namespace Hash
|
||||||
{
|
{
|
||||||
return std::make_unique<CngHashAlgorithm<Sha256Algorithm>>(BCRYPT_SHA256_ALGORITHM);
|
return std::make_unique<CngHashAlgorithm<Sha256Algorithm>>(BCRYPT_SHA256_ALGORITHM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RsaAlgorithm> CreateRSA()
|
||||||
|
{
|
||||||
|
return std::make_unique<CngRsaAlgorithm>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<RsaKey> CreateRSAKey()
|
||||||
|
{
|
||||||
|
return std::make_unique<CngRsaKey>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#define __USE_CNG__
|
#define __USE_CNG__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef __USE_CNG__
|
|
||||||
#ifndef __USE_CNG__
|
#ifndef __USE_CNG__
|
||||||
|
|
||||||
#include "Crypt.h"
|
#include "Crypt.h"
|
||||||
|
|
|
@ -66,4 +66,11 @@ namespace Hash
|
||||||
->Update(data, dataLen)
|
->Update(data, dataLen)
|
||||||
->Finish();
|
->Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Sha256Algorithm::Result SHA256(const void * data, size_t dataLen)
|
||||||
|
{
|
||||||
|
return CreateSHA256()
|
||||||
|
->Update(data, dataLen)
|
||||||
|
->Finish();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue