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>
|
||||
</ClCompile>
|
||||
<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>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
|
|
@ -18,22 +18,38 @@
|
|||
#define __USE_CNG__
|
||||
#endif
|
||||
|
||||
#undef __USE_CNG__
|
||||
|
||||
#ifdef __USE_CNG__
|
||||
|
||||
#include "Crypt.h"
|
||||
#include "../platform/Platform2.h"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
// CNG: Cryptography API: Next Generation (CNG)
|
||||
// available in Windows Vista onwards.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
#include <ncrypt.h>
|
||||
#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>
|
||||
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<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
|
||||
{
|
||||
std::unique_ptr<Sha1Algorithm> CreateSHA1()
|
||||
|
@ -149,6 +239,16 @@ namespace Hash
|
|||
{
|
||||
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
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#define __USE_CNG__
|
||||
#endif
|
||||
|
||||
#undef __USE_CNG__
|
||||
#ifndef __USE_CNG__
|
||||
|
||||
#include "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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue