diff --git a/src/hx/libs/ssl/windows/Cng.h b/src/hx/libs/ssl/windows/Cng.h new file mode 100644 index 000000000..cf3dc993b --- /dev/null +++ b/src/hx/libs/ssl/windows/Cng.h @@ -0,0 +1,168 @@ +#pragma once + +#include +#include "Utils.h" +#include "bcrypt.h" + +namespace hx +{ + namespace ssl + { + namespace windows + { + template + T getProperty(BCRYPT_HANDLE handle, const wchar_t* prop) + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + auto size = ULONG{ 0 }; + if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, prop, nullptr, 0, &size, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to get property size : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + auto buffer = std::vector(size); + if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, prop, buffer.data(), buffer.size(), &size, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to get property : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + + return static_cast(buffer[0]); + } + + struct CngHash + { + BCRYPT_HASH_HANDLE handle; + std::unique_ptr> object; + + CngHash(BCRYPT_HASH_HANDLE inHandle, std::unique_ptr> inObject) + : handle(inHandle) + , object(std::move(inObject)) + { + // + } + + ~CngHash() + { + BCryptDestroyHash(handle); + } + + void hash(const Array& input) const + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + if (!BCRYPT_SUCCESS(result = BCryptHashData(handle, reinterpret_cast(input->getBase()), input->length, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to hash data : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + } + + void hash(const PUCHAR input, const ULONG length) const + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + if (!BCRYPT_SUCCESS(result = BCryptHashData(handle, input, length, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to hash data : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + } + + void finish(PUCHAR output, const ULONG length) const + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + if (!BCRYPT_SUCCESS(result = BCryptFinishHash(handle, output, length, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to finish hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + } + + Array finish() const + { + auto result = DWORD{ 0 }; + auto length = getProperty(handle, BCRYPT_HASH_LENGTH); + auto output = Array(length, length); + + hx::EnterGCFreeZone(); + + if (!BCRYPT_SUCCESS(result = BCryptFinishHash(handle, reinterpret_cast(output->getBase()), output->length, 0))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to finish hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + + return output; + } + }; + + struct CngAlgorithm + { + CngAlgorithm(BCRYPT_ALG_HANDLE inHandle) : handle(inHandle) {} + + public: + BCRYPT_ALG_HANDLE handle; + + ~CngAlgorithm() + { + BCryptCloseAlgorithmProvider(handle, 0); + } + + std::unique_ptr hash() + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + auto hHash = BCRYPT_HASH_HANDLE(); + auto object = std::make_unique>(getProperty(handle, BCRYPT_OBJECT_LENGTH)); + + if (!BCRYPT_SUCCESS(result = BCryptCreateHash(handle, &hHash, object->data(), object->size(), nullptr, 0, BCRYPT_HASH_REUSABLE_FLAG))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to create hash object : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + + return std::make_unique(hHash, std::move(object)); + } + + static std::unique_ptr create(const wchar_t* algId) + { + hx::EnterGCFreeZone(); + + auto result = DWORD{ 0 }; + auto handle = BCRYPT_ALG_HANDLE(); + + if (!BCRYPT_SUCCESS(result = BCryptOpenAlgorithmProvider(&handle, algId, nullptr, BCRYPT_HASH_REUSABLE_FLAG))) + { + hx::ExitGCFreeZone(); + hx::Throw(HX_CSTRING("Failed to open algorithm provider : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); + } + + hx::ExitGCFreeZone(); + + return std::make_unique(handle); + } + }; + } + } +} diff --git a/src/hx/libs/ssl/windows/Digest.cpp b/src/hx/libs/ssl/windows/Digest.cpp index ce9cfe28f..8842c4993 100644 --- a/src/hx/libs/ssl/windows/Digest.cpp +++ b/src/hx/libs/ssl/windows/Digest.cpp @@ -2,156 +2,40 @@ #include #include "SSL.h" -#include "Utils.h" +#include "Cng.h" -Array _hx_ssl_dgst_make(Array buffer, String alg) +Array _hx_ssl_dgst_make(Array buffer, String algId) { - auto handle = BCRYPT_ALG_HANDLE(); - auto result = 0; - auto cb = DWORD{ 0 }; - hx::strbuf buf; - auto algorithm = alg.wchar_str(&buf); - - hx::EnterGCFreeZone(); - - if (!BCRYPT_SUCCESS(result = BCryptOpenAlgorithmProvider(&handle, algorithm, nullptr, 0))) - { - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to open algorithm provider : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto objectLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_OBJECT_LENGTH, reinterpret_cast(&objectLength), sizeof(DWORD), &cb, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto object = std::vector(objectLength); - auto hash = BCRYPT_HASH_HANDLE(); - if (!BCRYPT_SUCCESS(result = BCryptCreateHash(handle, &hash, object.data(), object.size(), nullptr, 0, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to create hash object : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + auto algorithm = hx::ssl::windows::CngAlgorithm::create(algId.wchar_str(&buf)); + auto hash = algorithm->hash(); - auto hashLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_HASH_LENGTH, reinterpret_cast(&hashLength), sizeof(DWORD), &cb, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + hash->hash(buffer); - if (!BCRYPT_SUCCESS(result = BCryptHashData(hash, reinterpret_cast(buffer->GetBase()), buffer->length, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to hash data : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - hx::ExitGCFreeZone(); - auto output = Array(hashLength, hashLength); - hx::EnterGCFreeZone(); - - if (!BCRYPT_SUCCESS(result = BCryptFinishHash(hash, reinterpret_cast(output->GetBase()), output->length, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to finish hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - - return output; + return hash->finish(); } -Array _hx_ssl_dgst_sign(Array buffer, Dynamic hpkey, String alg) +Array _hx_ssl_dgst_sign(Array buffer, Dynamic hpkey, String algId) { - auto key = hpkey.Cast(); - auto result = 0; - auto dummy = DWORD{ 0 }; hx::strbuf buf; - auto algorithm = alg.wchar_str(&buf); - auto padding = BCRYPT_PKCS1_PADDING_INFO{ algorithm }; - - hx::EnterGCFreeZone(); - auto handle = BCRYPT_ALG_HANDLE(); - if (!BCRYPT_SUCCESS(result = BCryptOpenAlgorithmProvider(&handle, algorithm, nullptr, 0))) - { - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to open algorithm provider : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto objectLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_OBJECT_LENGTH, reinterpret_cast(&objectLength), sizeof(DWORD), &dummy, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto object = std::vector(objectLength); - auto hash = BCRYPT_HASH_HANDLE(); - if (!BCRYPT_SUCCESS(result = BCryptCreateHash(handle, &hash, object.data(), object.size(), nullptr, 0, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to create hash object : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto hashLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_HASH_LENGTH, reinterpret_cast(&hashLength), sizeof(DWORD), &dummy, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - if (!BCRYPT_SUCCESS(result = BCryptHashData(hash, reinterpret_cast(buffer->GetBase()), buffer->length, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to hash data : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + auto key = hpkey.Cast(); + auto algorithm = algId.wchar_str(&buf); + auto alg = hx::ssl::windows::CngAlgorithm::create(algorithm); + auto hash = alg->hash(); + auto hashed = std::vector(hx::ssl::windows::getProperty(hash->handle, BCRYPT_HASH_LENGTH)); - auto hashed = std::vector(hashLength); - if (!BCRYPT_SUCCESS(result = BCryptFinishHash(hash, reinterpret_cast(hashed.data()), hashed.size(), 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); + hash->hash(buffer); + hash->finish(hashed.data(), hashed.size()); - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to finish hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + hx::EnterGCFreeZone(); + auto result = DWORD{ 0 }; + auto padding = BCRYPT_PKCS1_PADDING_INFO{ algorithm }; auto signatureLength = DWORD{ 0 }; if (ERROR_SUCCESS != (result = NCryptSignHash(key->ctx, &padding, reinterpret_cast(hashed.data()), hashed.size(), nullptr, 0, &signatureLength, BCRYPT_PAD_PKCS1))) { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - hx::ExitGCFreeZone(); hx::Throw(HX_CSTRING("Failed to signature length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); } @@ -162,88 +46,32 @@ Array _hx_ssl_dgst_sign(Array buffer, Dynamic hpke if (ERROR_SUCCESS != (result = NCryptSignHash(key->ctx, &padding, reinterpret_cast(hashed.data()), hashed.size(), reinterpret_cast(signature->GetBase()), signature->length, &signatureLength, BCRYPT_PAD_PKCS1))) { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - hx::ExitGCFreeZone(); hx::Throw(HX_CSTRING("Failed to sign hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); } - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - hx::ExitGCFreeZone(); return signature; } -bool _hx_ssl_dgst_verify(Array buffer, Array sign, Dynamic hpkey, String alg) +bool _hx_ssl_dgst_verify(Array buffer, Array sign, Dynamic hpkey, String algId) { - auto key = hpkey.Cast(); - auto handle = BCRYPT_ALG_HANDLE(); - auto result = 0; - auto cb = DWORD{ 0 }; hx::strbuf buf; - auto algorithm = alg.wchar_str(&buf); - auto padding = BCRYPT_PKCS1_PADDING_INFO{ algorithm }; - - hx::EnterGCFreeZone(); - - if (!BCRYPT_SUCCESS(result = BCryptOpenAlgorithmProvider(&handle, algorithm, nullptr, 0))) - { - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to open algorithm provider : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto objectLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_OBJECT_LENGTH, reinterpret_cast(&objectLength), sizeof(DWORD), &cb, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto object = std::vector(objectLength); - auto hash = BCRYPT_HASH_HANDLE(); - if (!BCRYPT_SUCCESS(result = BCryptCreateHash(handle, &hash, object.data(), object.size(), nullptr, 0, 0))) - { - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to create hash object : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - auto hashLength = DWORD{ 0 }; - if (!BCRYPT_SUCCESS(result = BCryptGetProperty(handle, BCRYPT_HASH_LENGTH, reinterpret_cast(&hashLength), sizeof(DWORD), &cb, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to get object length : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } - - if (!BCRYPT_SUCCESS(result = BCryptHashData(hash, reinterpret_cast(buffer->GetBase()), buffer->length, 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); - - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to hash data : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + auto key = hpkey.Cast(); + auto algorithm = algId.wchar_str(&buf); + auto alg = hx::ssl::windows::CngAlgorithm::create(algorithm); + auto hash = alg->hash(); + auto hashed = std::vector(hx::ssl::windows::getProperty(hash->handle, BCRYPT_HASH_LENGTH)); - auto output = std::vector(hashLength); - if (!BCRYPT_SUCCESS(result = BCryptFinishHash(hash, reinterpret_cast(output.data()), output.size(), 0))) - { - BCryptDestroyHash(hash); - BCryptCloseAlgorithmProvider(handle, 0); + hash->hash(buffer); + hash->finish(hashed.data(), hashed.size()); - hx::ExitGCFreeZone(); - hx::Throw(HX_CSTRING("Failed to finish hash : ") + hx::ssl::windows::utils::NTStatusErrorToString(result)); - } + hx::EnterGCFreeZone(); - auto success = ERROR_SUCCESS == NCryptVerifySignature(key->ctx, &padding, output.data(), output.size(), reinterpret_cast(sign->GetBase()), sign->length, BCRYPT_PAD_PKCS1); + auto padding = BCRYPT_PKCS1_PADDING_INFO{ algorithm }; + auto success = ERROR_SUCCESS == NCryptVerifySignature(key->ctx, &padding, hashed.data(), hashed.size(), reinterpret_cast(sign->GetBase()), sign->length, BCRYPT_PAD_PKCS1); hx::ExitGCFreeZone();