diff --git a/K7Pal/K7Pal.def b/K7Pal/K7Pal.def index fd5257bb..1e6564bf 100644 --- a/K7Pal/K7Pal.def +++ b/K7Pal/K7Pal.def @@ -1,3 +1,9 @@ LIBRARY EXPORTS + +K7PalHashCreate +K7PalHashDestroy +K7PalHashUpdate +K7PalHashFinal +K7PalHashGetSize diff --git a/K7Pal/K7Pal.h b/K7Pal/K7Pal.h index f41b4c23..d21d7511 100644 --- a/K7Pal/K7Pal.h +++ b/K7Pal/K7Pal.h @@ -13,4 +13,30 @@ #include +DECLARE_HANDLE(K7_PAL_HASH_HANDLE); +typedef K7_PAL_HASH_HANDLE *PK7_PAL_HASH_HANDLE; + +EXTERN_C HRESULT WINAPI K7PalHashCreate( + _Inout_ PK7_PAL_HASH_HANDLE HashHandle, + _In_ LPCWSTR AlgorithmIdentifier, + _In_opt_ PVOID SecretBuffer, + _In_ UINT32 SecretSize); + +EXTERN_C HRESULT WINAPI K7PalHashDestroy( + _Inout_ K7_PAL_HASH_HANDLE HashHandle); + +EXTERN_C HRESULT WINAPI K7PalHashUpdate( + _Inout_ K7_PAL_HASH_HANDLE HashHandle, + _In_ PVOID InputBuffer, + _In_ UINT32 InputSize); + +EXTERN_C HRESULT WINAPI K7PalHashFinal( + _Inout_ K7_PAL_HASH_HANDLE HashHandle, + _Out_ PVOID OutputBuffer, + _In_ ULONG OutputSize); + +EXTERN_C HRESULT WINAPI K7PalHashGetSize( + _In_ K7_PAL_HASH_HANDLE HashHandle, + _Out_ PUINT32 HashSize); + #endif // !K7_PAL diff --git a/K7Pal/K7PalHash.cpp b/K7Pal/K7PalHash.cpp index 6301ae92..47b778a7 100644 --- a/K7Pal/K7PalHash.cpp +++ b/K7Pal/K7PalHash.cpp @@ -9,3 +9,305 @@ */ #include "K7Pal.h" + +#include + +#include +#pragma comment(lib, "bcrypt.lib") + +#include +#include + +namespace +{ + typedef struct _K7_PAL_HASH_CONTEXT + { + UINT32 ContextSize; + UINT32 SecretSize; + PVOID SecretBuffer; + LPWSTR AlgorithmIdentifier; + BCRYPT_ALG_HANDLE AlgorithmHandle; + PVOID HashObject; + UINT32 HashSize; + UINT32 Reserved; + BCRYPT_HASH_HANDLE HashHandle; + } K7_PAL_HASH_CONTEXT, *PK7_PAL_HASH_CONTEXT; + + static PK7_PAL_HASH_CONTEXT K7PalHashInternalGetContextFromHandle( + _In_opt_ K7_PAL_HASH_HANDLE HashHandle) + { + if (HashHandle) + { + PK7_PAL_HASH_CONTEXT Context = + reinterpret_cast(HashHandle); + if (sizeof(K7_PAL_HASH_CONTEXT) == Context->ContextSize) + { + return Context; + } + } + + return nullptr; + } + + static bool K7PalHashInternalInitializeVolatileContext( + _Inout_ PK7_PAL_HASH_CONTEXT Context) + { + if (!BCRYPT_SUCCESS(::BCryptOpenAlgorithmProvider( + &Context->AlgorithmHandle, + Context->AlgorithmIdentifier, + nullptr, + Context->SecretBuffer ? BCRYPT_ALG_HANDLE_HMAC_FLAG : 0))) + { + return false; + } + + DWORD HashObjectSize = 0; + { + DWORD ReturnLength = 0; + if (!BCRYPT_SUCCESS(::BCryptGetProperty( + Context->AlgorithmHandle, + BCRYPT_OBJECT_LENGTH, + reinterpret_cast(&HashObjectSize), + sizeof(HashObjectSize), + &ReturnLength, + 0))) + { + return false; + } + } + + DWORD HashSize = 0; + { + DWORD ReturnLength = 0; + if (!BCRYPT_SUCCESS(::BCryptGetProperty( + Context->AlgorithmHandle, + BCRYPT_HASH_LENGTH, + reinterpret_cast(&HashSize), + sizeof(HashSize), + &ReturnLength, + 0))) + { + return false; + } + } + Context->HashSize = HashSize; + + Context->HashObject = ::MileAllocateMemory(HashObjectSize); + if (!Context->HashObject) + { + return false; + } + + return BCRYPT_SUCCESS(::BCryptCreateHash( + Context->AlgorithmHandle, + &Context->HashHandle, + reinterpret_cast(Context->HashObject), + HashObjectSize, + Context->SecretBuffer + ? reinterpret_cast(Context->SecretBuffer) + : nullptr, + Context->SecretBuffer + ? Context->SecretSize + : 0, + 0)); + } + + static void K7PalHashInternalUninitializeVolatileContext( + _Inout_ PK7_PAL_HASH_CONTEXT Context) + { + Context->HashSize = 0; + + if (Context->HashHandle) + { + ::BCryptDestroyHash(Context->HashHandle); + Context->HashHandle = nullptr; + } + + if (Context->HashObject) + { + ::MileFreeMemory(Context->HashObject); + Context->HashObject = nullptr; + } + + if (Context->AlgorithmHandle) + { + ::BCryptCloseAlgorithmProvider(Context->AlgorithmHandle, 0); + Context->AlgorithmHandle = nullptr; + } + } + + static void K7PalHashInternalUninitializeContext( + _Inout_ PK7_PAL_HASH_CONTEXT Context) + { + Context->ContextSize = 0; + + ::K7PalHashInternalUninitializeVolatileContext(Context); + + Context->SecretSize = 0; + + if (Context->SecretBuffer) + { + ::MileFreeMemory(Context->SecretBuffer); + Context->SecretBuffer = nullptr; + } + + if (Context->AlgorithmIdentifier) + { + ::MileFreeMemory(Context->AlgorithmIdentifier); + Context->AlgorithmIdentifier = nullptr; + } + } +} + +EXTERN_C HRESULT WINAPI K7PalHashCreate( + _Inout_ PK7_PAL_HASH_HANDLE HashHandle, + _In_ LPCWSTR AlgorithmIdentifier, + _In_opt_ PVOID SecretBuffer, + _In_ UINT32 SecretSize) +{ + if (!AlgorithmIdentifier) + { + return E_INVALIDARG; + } + + if (!HashHandle) + { + return E_INVALIDARG; + } + *HashHandle = nullptr; + + bool Result = false; + + do + { + PK7_PAL_HASH_CONTEXT Context = reinterpret_cast( + ::MileAllocateMemory(sizeof(K7_PAL_HASH_CONTEXT))); + if (!Context) + { + break; + } + *HashHandle = reinterpret_cast(Context); + Context->ContextSize = sizeof(sizeof(K7_PAL_HASH_CONTEXT)); + + SIZE_T AlgorithmIdentifierSize = + sizeof(wchar_t) * (std::wcslen(AlgorithmIdentifier) + 1); + Context->AlgorithmIdentifier = reinterpret_cast( + ::MileAllocateMemory(AlgorithmIdentifierSize)); + if (!Context->AlgorithmIdentifier) + { + break; + } + std::memcpy( + Context->AlgorithmIdentifier, + AlgorithmIdentifier, + AlgorithmIdentifierSize); + + if (SecretBuffer) + { + Context->SecretBuffer = ::MileAllocateMemory(SecretSize); + if (!Context->SecretBuffer) + { + break; + } + Context->SecretSize = SecretSize; + } + + Result = ::K7PalHashInternalInitializeVolatileContext(Context); + + } while (false); + + if (!Result) + { + ::K7PalHashDestroy(*HashHandle); + *HashHandle = nullptr; + } + + return Result ? S_OK : E_FAIL; +} + +EXTERN_C HRESULT WINAPI K7PalHashDestroy( + _Inout_ K7_PAL_HASH_HANDLE HashHandle) +{ + PK7_PAL_HASH_CONTEXT Context = + ::K7PalHashInternalGetContextFromHandle(HashHandle); + if (!Context) + { + return E_INVALIDARG; + } + + ::K7PalHashInternalUninitializeContext(Context); + ::MileFreeMemory(Context); + return S_OK; +} + +EXTERN_C HRESULT WINAPI K7PalHashUpdate( + _Inout_ K7_PAL_HASH_HANDLE HashHandle, + _In_ PVOID InputBuffer, + _In_ UINT32 InputSize) +{ + PK7_PAL_HASH_CONTEXT Context = + ::K7PalHashInternalGetContextFromHandle(HashHandle); + if (!Context) + { + return E_INVALIDARG; + } + + bool Result = BCRYPT_SUCCESS(::BCryptHashData( + Context->HashHandle, + reinterpret_cast(InputBuffer), + InputSize, + 0)); + + return Result ? S_OK : E_FAIL; +} + +EXTERN_C HRESULT WINAPI K7PalHashFinal( + _Inout_ K7_PAL_HASH_HANDLE HashHandle, + _Out_ PVOID OutputBuffer, + _In_ ULONG OutputSize) +{ + PK7_PAL_HASH_CONTEXT Context = + ::K7PalHashInternalGetContextFromHandle(HashHandle); + if (!Context) + { + return E_INVALIDARG; + } + + bool Result = BCRYPT_SUCCESS(::BCryptFinishHash( + Context->HashHandle, + reinterpret_cast(OutputBuffer), + OutputSize, + 0)); + if (!Result) + { + if (OutputBuffer) + { + std::memset(OutputBuffer, 0, OutputSize); + } + } + + ::K7PalHashInternalUninitializeVolatileContext(Context); + ::K7PalHashInternalInitializeVolatileContext(Context); + + return Result ? S_OK : E_FAIL; +} + +EXTERN_C HRESULT WINAPI K7PalHashGetSize( + _In_ K7_PAL_HASH_HANDLE HashHandle, + _Out_ PUINT32 HashSize) +{ + if (!HashSize) + { + return E_INVALIDARG; + } + + PK7_PAL_HASH_CONTEXT Context = + ::K7PalHashInternalGetContextFromHandle(HashHandle); + if (!Context) + { + return E_INVALIDARG; + } + + *HashSize = Context->HashSize; + return S_OK; +}