1 /*
2  * PROJECT:     ReactOS API tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Tests for basic hash APIs
5  * COPYRIGHT:   Copyright 2023 Ratin Gao <ratin@knsoft.org>
6  */
7 
8 #include "precomp.h"
9 
10 typedef struct _A_SHA_CTX
11 {
12     UCHAR Buffer[64];
13     ULONG State[5];
14     ULONG Count[2];
15 } A_SHA_CTX, *PA_SHA_CTX;
16 
17 #define A_SHA_DIGEST_LEN 20
18 
19 typedef struct _MD5_CTX
20 {
21     ULONG Count[2];
22     ULONG State[4];
23     UCHAR Buffer[64];
24     UCHAR Hash[16];
25 } MD5_CTX, *PMD5_CTX;
26 
27 #define MD5_DIGEST_LEN 16
28 
29 typedef struct _MD4_CTX
30 {
31     ULONG State[4];
32     ULONG Count[2];
33     UCHAR Buffer[64];
34     UCHAR Hash[16];
35 } MD4_CTX, *PMD4_CTX;
36 
37 #define MD4_DIGEST_LEN 16
38 
39 #ifndef RSA32API
40 #define RSA32API __stdcall
41 #endif
42 
43 typedef
44 VOID
45 RSA32API
46 FN_A_SHAInit(
47     _Out_ PA_SHA_CTX Context);
48 
49 typedef
50 VOID
51 RSA32API
52 FN_A_SHAUpdate(
53     _Inout_ PA_SHA_CTX Context,
54     _In_reads_(BufferSize) PUCHAR Buffer,
55     _In_ ULONG BufferSize);
56 
57 typedef
58 VOID
59 RSA32API
60 FN_A_SHAFinal(
61     _Inout_ PA_SHA_CTX Context,
62     _Out_ PUCHAR Result);
63 
64 typedef
65 VOID
66 RSA32API
67 FN_MD5Init(
68     _Out_ PMD5_CTX Context);
69 
70 typedef
71 VOID
72 RSA32API
73 FN_MD5Update(
74     _Inout_ PMD5_CTX Context,
75     _In_reads_(BufferSize) PUCHAR Buffer,
76     _In_ ULONG BufferSize);
77 
78 typedef
79 VOID
80 RSA32API
81 FN_MD5Final(
82     _Inout_ PMD5_CTX Context);
83 
84 typedef
85 VOID
86 RSA32API
87 FN_MD4Init(
88     _Out_ PMD4_CTX Context);
89 
90 typedef
91 VOID
92 RSA32API
93 FN_MD4Update(
94     _Inout_ PMD4_CTX Context,
95     _In_reads_(BufferSize) PUCHAR Buffer,
96     _In_ ULONG BufferSize);
97 
98 typedef
99 VOID
100 RSA32API
101 FN_MD4Final(
102     _Inout_ PMD4_CTX Context);
103 
104 static HMODULE g_hAdvapi32 = NULL;
105 static ANSI_STRING g_TestString = RTL_CONSTANT_STRING("ReactOS Hash API Test String");
106 
107 static ULONG g_ctxSHA1StateInit[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
108 static UCHAR g_aucSHA1Result[A_SHA_DIGEST_LEN] = {
109     0xEC, 0x05, 0x43, 0xE7, 0xDE, 0x8A, 0xEE, 0xFF,
110     0xAD, 0x72, 0x2B, 0x9D, 0x55, 0x4F, 0xCA, 0x6A,
111     0x8D, 0x81, 0xF1, 0xC7
112 };
113 
114 static ULONG g_aulMD5Or4StateInit[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476 };
115 static UCHAR g_aucMD5Result[MD5_DIGEST_LEN] = {
116     0x3D, 0xE8, 0x23, 0x8B, 0x9D, 0xE0, 0xCE, 0x48,
117     0xB1, 0x1B, 0xDD, 0xD9, 0xC6, 0x86, 0xB2, 0xDE
118 };
119 static UCHAR g_aucMD4Result[MD4_DIGEST_LEN] = {
120     0xE0, 0xE8, 0x50, 0x8A, 0x4D, 0x11, 0x02, 0xA6,
121     0x6A, 0xF0, 0xA7, 0xAB, 0xD8, 0xC4, 0x40, 0xED
122 };
123 
124 static void Test_SHA1(void)
125 {
126     FN_A_SHAInit* pfnA_SHAInit;
127     FN_A_SHAUpdate* pfnA_SHAUpdate;
128     FN_A_SHAFinal* pfnA_SHAFinal;
129     DECLSPEC_ALIGN(4) A_SHA_CTX ctx;
130     UCHAR Result[A_SHA_DIGEST_LEN];
131     SIZE_T ComparedSize;
132 
133     /* Load functions */
134     pfnA_SHAInit = (FN_A_SHAInit*)GetProcAddress(g_hAdvapi32, "A_SHAInit");
135     pfnA_SHAUpdate = (FN_A_SHAUpdate*)GetProcAddress(g_hAdvapi32, "A_SHAUpdate");
136     pfnA_SHAFinal = (FN_A_SHAFinal*)GetProcAddress(g_hAdvapi32, "A_SHAFinal");
137 
138     if (!pfnA_SHAInit || !pfnA_SHAUpdate || !pfnA_SHAFinal)
139     {
140         skip("advapi32.dll!A_SHA*** not found\n");
141         return;
142     }
143 
144     /* Test A_SHAInit */
145     pfnA_SHAInit(&ctx);
146     ComparedSize = RtlCompareMemory(ctx.State,
147                                     g_ctxSHA1StateInit,
148                                     RTL_FIELD_SIZE(A_SHA_CTX, State));
149     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State));
150     ok_eq_ulong(ctx.Count[0], 0UL);
151     ok_eq_ulong(ctx.Count[1], 0UL);
152 
153     /* Test A_SHAUpdate */
154     pfnA_SHAUpdate(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length);
155     ComparedSize = RtlCompareMemory(ctx.Buffer,
156                                     g_TestString.Buffer,
157                                     g_TestString.Length);
158     ok_eq_size(ComparedSize, g_TestString.Length);
159     ComparedSize = RtlCompareMemory(ctx.State,
160                                     g_ctxSHA1StateInit,
161                                     RTL_FIELD_SIZE(A_SHA_CTX, State));
162     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State));
163     ok_eq_ulong(ctx.Count[0], 0UL);
164     ok_eq_ulong(ctx.Count[1], (ULONG)g_TestString.Length);
165 
166     /* Test A_SHAFinal */
167     pfnA_SHAFinal(&ctx, Result);
168     ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0);
169     ok_eq_size(ComparedSize, sizeof(ctx.Buffer));
170     ComparedSize = RtlCompareMemory(ctx.State,
171                                     g_ctxSHA1StateInit,
172                                     RTL_FIELD_SIZE(A_SHA_CTX, State));
173     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(A_SHA_CTX, State));
174     ok_eq_ulong(ctx.Count[0], 0UL);
175     ok_eq_ulong(ctx.Count[1], 0UL);
176     ComparedSize = RtlCompareMemory(Result, g_aucSHA1Result, A_SHA_DIGEST_LEN);
177     ok_eq_size(ComparedSize, A_SHA_DIGEST_LEN);
178 }
179 
180 static void Test_MD5(void)
181 {
182     FN_MD5Init* pfnMD5Init;
183     FN_MD5Update* pfnMD5Update;
184     FN_MD5Final* pfnMD5Final;
185     DECLSPEC_ALIGN(4) MD5_CTX ctx;
186     SIZE_T ComparedSize;
187 
188     /* Load functions */
189     pfnMD5Init = (FN_MD5Init*)GetProcAddress(g_hAdvapi32, "MD5Init");
190     pfnMD5Update = (FN_MD5Update*)GetProcAddress(g_hAdvapi32, "MD5Update");
191     pfnMD5Final = (FN_MD5Final*)GetProcAddress(g_hAdvapi32, "MD5Final");
192 
193     if (!pfnMD5Init || !pfnMD5Update || !pfnMD5Final)
194     {
195         skip("advapi32.dll!MD5*** not found\n");
196         return;
197     }
198 
199     /* Test MD5Init */
200     pfnMD5Init(&ctx);
201     ok_eq_ulong(ctx.Count[0], 0UL);
202     ok_eq_ulong(ctx.Count[1], 0UL);
203     ComparedSize = RtlCompareMemory(ctx.State,
204                                     g_aulMD5Or4StateInit,
205                                     RTL_FIELD_SIZE(MD5_CTX, State));
206     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD5_CTX, State));
207 
208     /* Test MD5Update */
209     pfnMD5Update(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length);
210     ComparedSize = RtlCompareMemory(ctx.Buffer,
211                                     g_TestString.Buffer,
212                                     g_TestString.Length);
213     ok_eq_size(ComparedSize, g_TestString.Length);
214     ComparedSize = RtlCompareMemory(ctx.State,
215                                     g_aulMD5Or4StateInit,
216                                     RTL_FIELD_SIZE(MD5_CTX, State));
217     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD5_CTX, State));
218     ok_eq_ulong(ctx.Count[0], (ULONG)g_TestString.Length * CHAR_BIT);
219     ok_eq_ulong(ctx.Count[1], 0UL);
220 
221     /* Test MD5Final */
222     pfnMD5Final(&ctx);
223     ok_eq_ulong(ctx.Count[0], 0x200UL);
224     ok_eq_ulong(ctx.Count[1], 0UL);
225     ok_eq_ulong(ctx.State[0], 0x8B23E83DUL);
226     ok_eq_ulong(ctx.State[1], 0x48CEE09DUL);
227     ok_eq_ulong(ctx.State[2], 0xD9DD1BB1UL);
228     ok_eq_ulong(ctx.State[3], 0xDEB286C6UL);
229     ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0);
230     ok_eq_size(ComparedSize, sizeof(ctx.Buffer));
231     ComparedSize = RtlCompareMemory(ctx.Hash, &g_aucMD5Result, MD5_DIGEST_LEN);
232     ok_eq_size(ComparedSize, MD5_DIGEST_LEN);
233 }
234 
235 static void Test_MD4(void)
236 {
237     FN_MD4Init* pfnMD4Init;
238     FN_MD4Update* pfnMD4Update;
239     FN_MD4Final* pfnMD4Final;
240     DECLSPEC_ALIGN(4) MD4_CTX ctx;
241     SIZE_T ComparedSize;
242 
243     /* Load functions */
244     pfnMD4Init = (FN_MD4Init*)GetProcAddress(g_hAdvapi32, "MD4Init");
245     pfnMD4Update = (FN_MD4Update*)GetProcAddress(g_hAdvapi32, "MD4Update");
246     pfnMD4Final = (FN_MD4Final*)GetProcAddress(g_hAdvapi32, "MD4Final");
247 
248     if (!pfnMD4Init || !pfnMD4Update || !pfnMD4Final)
249     {
250         skip("advapi32.dll!MD4*** not found\n");
251         return;
252     }
253 
254     /* Test MD4Init */
255     pfnMD4Init(&ctx);
256     ok_eq_ulong(ctx.Count[0], 0UL);
257     ok_eq_ulong(ctx.Count[1], 0UL);
258     ComparedSize = RtlCompareMemory(ctx.State,
259                                     g_aulMD5Or4StateInit,
260                                     RTL_FIELD_SIZE(MD4_CTX, State));
261     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD4_CTX, State));
262 
263     /* Test MD4Update */
264     pfnMD4Update(&ctx, (PUCHAR)g_TestString.Buffer, g_TestString.Length);
265     ComparedSize = RtlCompareMemory(ctx.Buffer,
266                                     g_TestString.Buffer,
267                                     g_TestString.Length);
268     ok_eq_size(ComparedSize, g_TestString.Length);
269     ComparedSize = RtlCompareMemory(ctx.State,
270                                     g_aulMD5Or4StateInit,
271                                     RTL_FIELD_SIZE(MD4_CTX, State));
272     ok_eq_size(ComparedSize, RTL_FIELD_SIZE(MD4_CTX, State));
273     ok_eq_ulong(ctx.Count[0], (ULONG)g_TestString.Length * CHAR_BIT);
274     ok_eq_ulong(ctx.Count[1], 0UL);
275 
276     /* Test MD4Final */
277     pfnMD4Final(&ctx);
278     ok_eq_ulong(ctx.Count[0], 0x200UL);
279     ok_eq_ulong(ctx.Count[1], 0UL);
280     ok_eq_ulong(ctx.State[0], 0x8A50E8E0UL);
281     ok_eq_ulong(ctx.State[1], 0xA602114DUL);
282     ok_eq_ulong(ctx.State[2], 0xABA7F06AUL);
283     ok_eq_ulong(ctx.State[3], 0xED40C4D8UL);
284     ComparedSize = RtlCompareMemoryUlong(ctx.Buffer, sizeof(ctx.Buffer), 0);
285     ok_eq_size(ComparedSize, sizeof(ctx.Buffer));
286     ComparedSize = RtlCompareMemory(ctx.Hash, &g_aucMD4Result, MD4_DIGEST_LEN);
287     ok_eq_size(ComparedSize, MD4_DIGEST_LEN);
288 }
289 
290 START_TEST(Hash)
291 {
292     /* Load advapi32.dll */
293     g_hAdvapi32 = GetModuleHandleW(L"advapi32.dll");
294     if (!g_hAdvapi32)
295     {
296         skip("Module advapi32 not found\n");
297         return;
298     }
299 
300     Test_SHA1();
301     Test_MD5();
302     Test_MD4();
303 }
304