From f61e14f554f5a1bad66b1e7bc26ab629db42fd4f Mon Sep 17 00:00:00 2001 From: Ratin Gao Date: Tue, 19 Dec 2023 01:35:30 +0800 Subject: [PATCH] [NTDLL][ADVAPI32][ADVAPI32_APITEST][CRYPTLIB] Add hash API exports for NT6+ and apitests with small fixes - For NT6.0+, NTDLL exports those hash APIs that ADVAPI32 thunks forward to - Fix undocumented context structure layout and content - Add apitests to verify both of hash result and structure content --- dll/ntdll/CMakeLists.txt | 3 + dll/ntdll/def/ntdll.spec | 18 +- dll/win32/advapi32/advapi32.spec | 27 +- .../rostests/apitests/advapi32/CMakeLists.txt | 1 + modules/rostests/apitests/advapi32/Hash.c | 303 ++++++++++++++++++ modules/rostests/apitests/advapi32/testlist.c | 2 + sdk/lib/cryptlib/md4.c | 1 + sdk/lib/cryptlib/md5.c | 1 + sdk/lib/cryptlib/sha1.c | 1 + sdk/lib/cryptlib/sha1.h | 7 +- 10 files changed, 342 insertions(+), 22 deletions(-) create mode 100644 modules/rostests/apitests/advapi32/Hash.c diff --git a/dll/ntdll/CMakeLists.txt b/dll/ntdll/CMakeLists.txt index 3fee0a79ce1..f416bb85ed7 100644 --- a/dll/ntdll/CMakeLists.txt +++ b/dll/ntdll/CMakeLists.txt @@ -62,6 +62,9 @@ set_subsystem(ntdll console) ################# END HACK ################# target_link_libraries(ntdll csrlib rtl rtl_um rtl_vista ntdllsys libcntpr uuid ${PSEH_LIB}) +if(DLL_EXPORT_VERSION GREATER_EQUAL 0x600) + target_link_libraries(ntdll cryptlib) +endif() if (STACK_PROTECTOR) target_sources(ntdll PRIVATE $) diff --git a/dll/ntdll/def/ntdll.spec b/dll/ntdll/def/ntdll.spec index d4ad13d38bc..aa1cf0ca734 100644 --- a/dll/ntdll/def/ntdll.spec +++ b/dll/ntdll/def/ntdll.spec @@ -10,9 +10,9 @@ @ stdcall -arch=i386 ExpInterlockedPopEntrySListEnd() @ stdcall -arch=i386 ExpInterlockedPopEntrySListFault() @ stdcall -arch=i386 ExpInterlockedPopEntrySListResume() -@ stdcall -stub -version=0x600+ A_SHAFinal(ptr ptr) -@ stdcall -stub -version=0x600+ A_SHAInit(ptr) -@ stdcall -stub -version=0x600+ A_SHAUpdate(ptr ptr long) +@ stdcall -version=0x600+ A_SHAFinal(ptr ptr) +@ stdcall -version=0x600+ A_SHAInit(ptr) +@ stdcall -version=0x600+ A_SHAUpdate(ptr ptr long) @ stdcall -stub -version=0x600+ AlpcAdjustCompletionListConcurrencyCount(ptr long) @ stdcall -stub -version=0x600+ AlpcFreeCompletionListMessage(ptr ptr) @ stdcall -stub -version=0x600+ AlpcGetCompletionListLastMessageInformation(ptr ptr ptr) @@ -191,12 +191,12 @@ @ stub -version=0x600+ LdrpResGetMappingSize @ stub -version=0x600+ LdrpResGetRCConfig @ stub -version=0x600+ LdrpResGetResourceDirectory -@ stdcall -stub -version=0x600+ MD4Final(ptr) -@ stdcall -stub -version=0x600+ MD4Init(ptr) -@ stdcall -stub -version=0x600+ MD4Update(ptr ptr long) -@ stdcall -stub -version=0x600+ MD5Final(ptr) -@ stdcall -stub -version=0x600+ MD5Init(ptr) -@ stdcall -stub -version=0x600+ MD5Update(ptr ptr long) +@ stdcall -version=0x600+ MD4Final(ptr) +@ stdcall -version=0x600+ MD4Init(ptr) +@ stdcall -version=0x600+ MD4Update(ptr ptr long) +@ stdcall -version=0x600+ MD5Final(ptr) +@ stdcall -version=0x600+ MD5Init(ptr) +@ stdcall -version=0x600+ MD5Update(ptr ptr long) @ extern NlsAnsiCodePage @ extern NlsMbCodePageTag @ extern NlsMbOemCodePageTag diff --git a/dll/win32/advapi32/advapi32.spec b/dll/win32/advapi32/advapi32.spec index e158d6a5c48..e79390f57ba 100644 --- a/dll/win32/advapi32/advapi32.spec +++ b/dll/win32/advapi32/advapi32.spec @@ -1,7 +1,10 @@ 1 stdcall I_ScGetCurrentGroupStateW(ptr wstr ptr) -@ stdcall A_SHAFinal(ptr ptr) -@ stdcall A_SHAInit(ptr) -@ stdcall A_SHAUpdate(ptr ptr long) +@ stdcall -version=0x502 A_SHAFinal(ptr ptr) +@ stdcall -version=0x600+ A_SHAFinal(ptr ptr) ntdll.A_SHAFinal +@ stdcall -version=0x502 A_SHAInit(ptr) +@ stdcall -version=0x600+ A_SHAInit(ptr) ntdll.A_SHAInit +@ stdcall -version=0x502 A_SHAUpdate(ptr ptr long) +@ stdcall -version=0x600+ A_SHAUpdate(ptr ptr long) ntdll.A_SHAUpdate @ stdcall AbortSystemShutdownA(ptr) @ stdcall AbortSystemShutdownW(ptr) @ stdcall AccessCheck(ptr long long ptr ptr ptr ptr ptr) @@ -405,12 +408,18 @@ @ stdcall LsaSetTrustedDomainInfoByName(ptr ptr long ptr) @ stdcall LsaSetTrustedDomainInformation(ptr ptr long ptr) @ stdcall LsaStorePrivateData(ptr ptr ptr) -@ stdcall MD4Final(ptr) -@ stdcall MD4Init(ptr) -@ stdcall MD4Update(ptr ptr long) -@ stdcall MD5Final(ptr) -@ stdcall MD5Init(ptr) -@ stdcall MD5Update(ptr ptr long) +@ stdcall -version=0x502 MD4Final(ptr) +@ stdcall -version=0x600+ MD4Final(ptr) ntdll.MD4Final +@ stdcall -version=0x502 MD4Init(ptr) +@ stdcall -version=0x600+ MD4Init(ptr) ntdll.MD4Init +@ stdcall -version=0x502 MD4Update(ptr ptr long) +@ stdcall -version=0x600+ MD4Update(ptr ptr long) ntdll.MD4Update +@ stdcall -version=0x502 MD5Final(ptr) +@ stdcall -version=0x600+ MD5Final(ptr) ntdll.MD5Final +@ stdcall -version=0x502 MD5Init(ptr) +@ stdcall -version=0x600+ MD5Init(ptr) ntdll.MD5Init +@ stdcall -version=0x502 MD5Update(ptr ptr long) +@ stdcall -version=0x600+ MD5Update(ptr ptr long) ntdll.MD5Update @ stub MSChapSrvChangePassword2 @ stub MSChapSrvChangePassword @ stdcall MakeAbsoluteSD2(ptr ptr) diff --git a/modules/rostests/apitests/advapi32/CMakeLists.txt b/modules/rostests/apitests/advapi32/CMakeLists.txt index 8a9bab7abd6..45c91859cb2 100644 --- a/modules/rostests/apitests/advapi32/CMakeLists.txt +++ b/modules/rostests/apitests/advapi32/CMakeLists.txt @@ -3,6 +3,7 @@ list(APPEND SOURCE CreateService.c DuplicateTokenEx.c eventlog.c + Hash.c HKEY_CLASSES_ROOT.c IsTextUnicode.c LockServiceDatabase.c diff --git a/modules/rostests/apitests/advapi32/Hash.c b/modules/rostests/apitests/advapi32/Hash.c new file mode 100644 index 00000000000..aa4a3b8cdf4 --- /dev/null +++ b/modules/rostests/apitests/advapi32/Hash.c @@ -0,0 +1,303 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Tests for basic hash APIs + * COPYRIGHT: Copyright 2023 Ratin Gao + */ + +#include "precomp.h" + +typedef struct _A_SHA_CTX +{ + UCHAR Buffer[64]; + ULONG State[5]; + ULONG Count[2]; +} A_SHA_CTX, *PA_SHA_CTX; + +#define A_SHA_DIGEST_LEN 20 + +typedef struct _MD5_CTX +{ + ULONG Count[2]; + ULONG State[4]; + UCHAR Buffer[64]; + UCHAR Hash[16]; +} MD5_CTX, *PMD5_CTX; + +#define MD5_DIGEST_LEN 16 + +typedef struct _MD4_CTX +{ + ULONG State[4]; + ULONG Count[2]; + UCHAR Buffer[64]; + UCHAR Hash[16]; +} MD4_CTX, *PMD4_CTX; + +#define MD4_DIGEST_LEN 16 + +#ifndef RSA32API +#define RSA32API __stdcall +#endif + +typedef +VOID +RSA32API +FN_A_SHAInit( + _Out_ PA_SHA_CTX Context); + +typedef +VOID +RSA32API +FN_A_SHAUpdate( + _Inout_ PA_SHA_CTX Context, + _In_reads_(BufferSize) PUCHAR Buffer, + _In_ ULONG BufferSize); + +typedef +VOID +RSA32API +FN_A_SHAFinal( + _Inout_ PA_SHA_CTX Context, + _Out_ PUCHAR Result); + +typedef +VOID +RSA32API +FN_MD5Init( + _Out_ PMD5_CTX Context); + +typedef +VOID +RSA32API +FN_MD5Update( + _Inout_ PMD5_CTX Context, + _In_reads_(BufferSize) PUCHAR Buffer, + _In_ ULONG BufferSize); + +typedef +VOID +RSA32API +FN_MD5Final( + _Inout_ PMD5_CTX Context); + +typedef +VOID +RSA32API +FN_MD4Init( + _Out_ PMD4_CTX Context); + +typedef +VOID +RSA32API +FN_MD4Update( + _Inout_ PMD4_CTX Context, + _In_reads_(BufferSize) PUCHAR Buffer, + _In_ ULONG BufferSize); + +typedef +VOID +RSA32API +FN_MD4Final( + _Inout_ PMD4_CTX Context); + +static HMODULE g_hAdvapi32 = NULL; +static ANSI_STRING g_TestString = RTL_CONSTANT_STRING("ReactOS Hash API Test String"); + +static ULONG g_ctxSHA1StateInit[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; +static UCHAR g_aucSHA1Result[A_SHA_DIGEST_LEN] = { + 0xEC, 0x05, 0x43, 0xE7, 0xDE, 0x8A, 0xEE, 0xFF, + 0xAD, 0x72, 0x2B, 0x9D, 0x55, 0x4F, 0xCA, 0x6A, + 0x8D, 0x81, 0xF1, 0xC7 +}; + +static ULONG g_aulMD5Or4StateInit[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 }; +static UCHAR g_aucMD5Result[MD5_DIGEST_LEN] = { + 0x3D, 0xE8, 0x23, 0x8B, 0x9D, 0xE0, 0xCE, 0x48, + 0xB1, 0x1B, 0xDD, 0xD9, 0xC6, 0x86, 0xB2, 0xDE +}; +static UCHAR g_aucMD4Result[MD4_DIGEST_LEN] = { + 0xE0, 0xE8, 0x50, 0x8A, 0x4D, 0x11, 0x02, 0xA6, + 0x6A, 0xF0, 0xA7, 0xAB, 0xD8, 0xC4, 0x40, 0xED +}; + +static void Test_SHA1(void) +{ + FN_A_SHAInit* pfnA_SHAInit; + FN_A_SHAUpdate* pfnA_SHAUpdate; + FN_A_SHAFinal* pfnA_SHAFinal; + DECLSPEC_ALIGN(4) A_SHA_CTX ctx; + UCHAR Result[A_SHA_DIGEST_LEN]; + SIZE_T ComparedSize; + + /* Load functions */ + pfnA_SHAInit = (FN_A_SHAInit*)GetProcAddress(g_hAdvapi32, "A_SHAInit"); + pfnA_SHAUpdate = (FN_A_SHAUpdate*)GetProcAddress(g_hAdvapi32, "A_SHAUpdate"); + pfnA_SHAFinal = (FN_A_SHAFinal*)GetProcAddress(g_hAdvapi32, "A_SHAFinal"); + + if (!pfnA_SHAInit || !pfnA_SHAUpdate || !pfnA_SHAFinal) + { + skip("advapi32.dll!A_SHA*** not found\n"); + return; + } + + /* Test A_SHAInit */ + pfnA_SHAInit(&ctx); + ComparedSize = RtlCompareMemory(ctx.State, + g_ctxSHA1StateInit, + RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_ulong(ctx.Count[0], 0UL); + ok_eq_ulong(ctx.Count[1], 0UL); + + /* Test A_SHAUpdate */ + pfnA_SHAUpdate(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.Buffer, + g_TestString.Buffer, + g_TestString.Length); + ok_eq_size(ComparedSize, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.State, + g_ctxSHA1StateInit, + RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_ulong(ctx.Count[0], 0UL); + ok_eq_ulong(ctx.Count[1], (ULONG)g_TestString.Length); + + /* Test A_SHAFinal */ + pfnA_SHAFinal(&ctx, Result); + ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0); + ok_eq_size(ComparedSize, sizeof(ctx.Buffer)); + ComparedSize = RtlCompareMemory(ctx.State, + g_ctxSHA1StateInit, + RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State)); + ok_eq_ulong(ctx.Count[0], 0UL); + ok_eq_ulong(ctx.Count[1], 0UL); + ComparedSize = RtlCompareMemory(Result, g_aucSHA1Result, A_SHA_DIGEST_LEN); + ok_eq_size(ComparedSize, A_SHA_DIGEST_LEN); +} + +static void Test_MD5(void) +{ + FN_MD5Init* pfnMD5Init; + FN_MD5Update* pfnMD5Update; + FN_MD5Final* pfnMD5Final; + DECLSPEC_ALIGN(4) MD5_CTX ctx; + SIZE_T ComparedSize; + + /* Load functions */ + pfnMD5Init = (FN_MD5Init*)GetProcAddress(g_hAdvapi32, "MD5Init"); + pfnMD5Update = (FN_MD5Update*)GetProcAddress(g_hAdvapi32, "MD5Update"); + pfnMD5Final = (FN_MD5Final*)GetProcAddress(g_hAdvapi32, "MD5Final"); + + if (!pfnMD5Init || !pfnMD5Update || !pfnMD5Final) + { + skip("advapi32.dll!MD5*** not found\n"); + return; + } + + /* Test MD5Init */ + pfnMD5Init(&ctx); + ok_eq_ulong(ctx.Count[0], 0UL); + ok_eq_ulong(ctx.Count[1], 0UL); + ComparedSize = RtlCompareMemory(ctx.State, + g_aulMD5Or4StateInit, + RTL_FIELD_SIZE(MD5_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD5_CTX, State)); + + /* Test MD5Update */ + pfnMD5Update(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.Buffer, + g_TestString.Buffer, + g_TestString.Length); + ok_eq_size(ComparedSize, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.State, + g_aulMD5Or4StateInit, + RTL_FIELD_SIZE(MD5_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD5_CTX, State)); + ok_eq_ulong(ctx.Count[0], (ULONG)g_TestString.Length * CHAR_BIT); + ok_eq_ulong(ctx.Count[1], 0UL); + + /* Test MD5Final */ + pfnMD5Final(&ctx); + ok_eq_ulong(ctx.Count[0], 0x200UL); + ok_eq_ulong(ctx.Count[1], 0UL); + ok_eq_ulong(ctx.State[0], 0x8B23E83DUL); + ok_eq_ulong(ctx.State[1], 0x48CEE09DUL); + ok_eq_ulong(ctx.State[2], 0xD9DD1BB1UL); + ok_eq_ulong(ctx.State[3], 0xDEB286C6UL); + ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0); + ok_eq_size(ComparedSize, sizeof(ctx.Buffer)); + ComparedSize = RtlCompareMemory(ctx.Hash, &g_aucMD5Result, MD5_DIGEST_LEN); + ok_eq_size(ComparedSize, MD5_DIGEST_LEN); +} + +static void Test_MD4(void) +{ + FN_MD4Init* pfnMD4Init; + FN_MD4Update* pfnMD4Update; + FN_MD4Final* pfnMD4Final; + DECLSPEC_ALIGN(4) MD4_CTX ctx; + SIZE_T ComparedSize; + + /* Load functions */ + pfnMD4Init = (FN_MD4Init*)GetProcAddress(g_hAdvapi32, "MD4Init"); + pfnMD4Update = (FN_MD4Update*)GetProcAddress(g_hAdvapi32, "MD4Update"); + pfnMD4Final = (FN_MD4Final*)GetProcAddress(g_hAdvapi32, "MD4Final"); + + if (!pfnMD4Init || !pfnMD4Update || !pfnMD4Final) + { + skip("advapi32.dll!MD4*** not found\n"); + return; + } + + /* Test MD4Init */ + pfnMD4Init(&ctx); + ok_eq_ulong(ctx.Count[0], 0UL); + ok_eq_ulong(ctx.Count[1], 0UL); + ComparedSize = RtlCompareMemory(ctx.State, + g_aulMD5Or4StateInit, + RTL_FIELD_SIZE(MD4_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD4_CTX, State)); + + /* Test MD4Update */ + pfnMD4Update(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.Buffer, + g_TestString.Buffer, + g_TestString.Length); + ok_eq_size(ComparedSize, g_TestString.Length); + ComparedSize = RtlCompareMemory(ctx.State, + g_aulMD5Or4StateInit, + RTL_FIELD_SIZE(MD4_CTX, State)); + ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD4_CTX, State)); + ok_eq_ulong(ctx.Count[0], (ULONG)g_TestString.Length * CHAR_BIT); + ok_eq_ulong(ctx.Count[1], 0UL); + + /* Test MD4Final */ + pfnMD4Final(&ctx); + ok_eq_ulong(ctx.Count[0], 0x200UL); + ok_eq_ulong(ctx.Count[1], 0UL); + ok_eq_ulong(ctx.State[0], 0x8A50E8E0UL); + ok_eq_ulong(ctx.State[1], 0xA602114DUL); + ok_eq_ulong(ctx.State[2], 0xABA7F06AUL); + ok_eq_ulong(ctx.State[3], 0xED40C4D8UL); + ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0); + ok_eq_size(ComparedSize, sizeof(ctx.Buffer)); + ComparedSize = RtlCompareMemory(ctx.Hash, &g_aucMD4Result, MD4_DIGEST_LEN); + ok_eq_size(ComparedSize, MD4_DIGEST_LEN); +} + +START_TEST(Hash) +{ + /* Load advapi32.dll */ + g_hAdvapi32 = GetModuleHandleW(L"advapi32.dll"); + if (!g_hAdvapi32) + { + skip("Module advapi32 not found\n"); + return; + } + + Test_SHA1(); + Test_MD5(); + Test_MD4(); +} diff --git a/modules/rostests/apitests/advapi32/testlist.c b/modules/rostests/apitests/advapi32/testlist.c index 67764a03204..a48b3b9d496 100644 --- a/modules/rostests/apitests/advapi32/testlist.c +++ b/modules/rostests/apitests/advapi32/testlist.c @@ -6,6 +6,7 @@ extern void func_CreateService(void); extern void func_DuplicateTokenEx(void); extern void func_eventlog(void); +extern void func_Hash(void); extern void func_HKEY_CLASSES_ROOT(void); extern void func_IsTextUnicode(void); extern void func_LockServiceDatabase(void); @@ -27,6 +28,7 @@ const struct test winetest_testlist[] = { "CreateService", func_CreateService }, { "DuplicateTokenEx", func_DuplicateTokenEx }, { "eventlog_supp", func_eventlog }, + { "Hash", func_Hash }, { "HKEY_CLASSES_ROOT", func_HKEY_CLASSES_ROOT }, { "IsTextUnicode" , func_IsTextUnicode }, { "LockServiceDatabase" , func_LockServiceDatabase }, diff --git a/sdk/lib/cryptlib/md4.c b/sdk/lib/cryptlib/md4.c index a553a20eb4e..8144a65abd6 100644 --- a/sdk/lib/cryptlib/md4.c +++ b/sdk/lib/cryptlib/md4.c @@ -152,6 +152,7 @@ VOID NTAPI MD4Final( MD4_CTX *ctx ) MD4Transform( ctx->buf, (unsigned int *)ctx->in ); byteReverse( (unsigned char *)ctx->buf, 4 ); memcpy( ctx->digest, ctx->buf, 16 ); + memset(ctx->in, 0, sizeof(ctx->in)); } /* The three core functions */ diff --git a/sdk/lib/cryptlib/md5.c b/sdk/lib/cryptlib/md5.c index a847997172a..02dca4e166e 100644 --- a/sdk/lib/cryptlib/md5.c +++ b/sdk/lib/cryptlib/md5.c @@ -152,6 +152,7 @@ VOID NTAPI MD5Final( MD5_CTX *ctx ) MD5Transform( ctx->buf, (unsigned int *)ctx->in ); byteReverse( (unsigned char *)ctx->buf, 4 ); memcpy( ctx->digest, ctx->buf, 16 ); + memset(ctx->in, 0, sizeof(ctx->in)); } /* The four core functions - F1 is optimized somewhat */ diff --git a/sdk/lib/cryptlib/sha1.c b/sdk/lib/cryptlib/sha1.c index ba9cd7ba488..90a33297c6c 100644 --- a/sdk/lib/cryptlib/sha1.c +++ b/sdk/lib/cryptlib/sha1.c @@ -194,5 +194,6 @@ A_SHAFinal(PSHA_CTX Context, PULONG Result) for (Index = 0; Index < 5; Index++) Result[Index] = DWORD2BE(Context->State[Index]); + memset(Context->Buffer, 0, sizeof(Context->Buffer)); A_SHAInit(Context); } diff --git a/sdk/lib/cryptlib/sha1.h b/sdk/lib/cryptlib/sha1.h index 519d03e5bb5..5ea49ec3bb0 100644 --- a/sdk/lib/cryptlib/sha1.h +++ b/sdk/lib/cryptlib/sha1.h @@ -11,10 +11,9 @@ extern "C" { /* SHA Context Structure Declaration */ typedef struct { - ULONG Unknown[6]; - ULONG State[5]; - ULONG Count[2]; - UCHAR Buffer[64]; + UCHAR Buffer[64]; + ULONG State[5]; + ULONG Count[2]; } SHA_CTX, *PSHA_CTX; VOID NTAPI