1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /*
13 Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
14 rights reserved.
15
16 License to copy and use this software is granted provided that it
17 is identified as the ""RSA Data Security, Inc. MD5 Message-Digest
18 Algorithm"" in all material mentioning or referencing this software
19 or this function.
20
21 License is also granted to make and use derivative works provided
22 that such works are identified as ""derived from the RSA Data
23 Security, Inc. MD5 Message-Digest Algorithm"" in all material
24 mentioning or referencing the derived work.
25
26 RSA Data Security, Inc. makes no representations concerning either
27 the merchantability of this software or the suitability of this
28 software for any particular purpose. It is provided ""as is""
29 without express or implied warranty of any kind.
30
31 These notices must be retained in any copies of any part of this
32 documentation and/or software.
33 */
34 /**************************************************************************/
35
36 /**************************************************************************/
37 /**************************************************************************/
38 /** */
39 /** NetX Component */
40 /** */
41 /** MD5 Digest Algorithm (MD5) */
42 /** */
43 /**************************************************************************/
44 /**************************************************************************/
45
46 #include "nx_api.h"
47 #include "nx_md5.h"
48
49 /* Define macros for the MD5 transform function. */
50
51 /* Define the MD5 basic F, G, H and I functions. */
52
53 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
54 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
55 #define H(x, y, z) ((x) ^ (y) ^ (z))
56 #define I(x, y, z) ((y) ^ ((x) | (~z)))
57
58
59 /* Define the MD5 left shift circular function. */
60
61 #define LEFT_SHIFT_CIRCULAR(x, n) (((x) << (n)) | ((x) >> (32-(n))))
62
63
64 /* Define the MD5 complex FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. */
65
66 #define FF(a, b, c, d, x, s, ac) { \
67 (a) += F ((b), (c), (d)) + (x) + (ULONG)(ac); \
68 (a) = LEFT_SHIFT_CIRCULAR ((a), (s)); \
69 (a) += (b); \
70 }
71 #define GG(a, b, c, d, x, s, ac) { \
72 (a) += G ((b), (c), (d)) + (x) + (ULONG)(ac); \
73 (a) = LEFT_SHIFT_CIRCULAR ((a), (s)); \
74 (a) += (b); \
75 }
76 #define HH(a, b, c, d, x, s, ac) { \
77 (a) += H ((b), (c), (d)) + (x) + (ULONG)(ac); \
78 (a) = LEFT_SHIFT_CIRCULAR ((a), (s)); \
79 (a) += (b); \
80 }
81 #define II(a, b, c, d, x, s, ac) { \
82 (a) += I ((b), (c), (d)) + (x) + (ULONG)(ac); \
83 (a) = LEFT_SHIFT_CIRCULAR ((a), (s)); \
84 (a) += (b); \
85 }
86
87
88 /* Define the padding array. This is used to pad the message such that its length is
89 64 bits shy of being a multiple of 512 bits long. */
90
91 UCHAR _nx_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
92
93
94 /**************************************************************************/
95 /* */
96 /* FUNCTION RELEASE */
97 /* */
98 /* _nx_md5_initialize PORTABLE C */
99 /* 6.1 */
100 /* AUTHOR */
101 /* */
102 /* Yuxin Zhou, Microsoft Corporation */
103 /* */
104 /* DESCRIPTION */
105 /* */
106 /* This function initializes the MD5 context. It must be called prior */
107 /* to creating the MD5 digest. */
108 /* */
109 /* INPUT */
110 /* */
111 /* context MD5 context pointer */
112 /* */
113 /* OUTPUT */
114 /* */
115 /* status Completion status */
116 /* */
117 /* CALLS */
118 /* */
119 /* None */
120 /* */
121 /* CALLED BY */
122 /* */
123 /* NetX Applications */
124 /* */
125 /* RELEASE HISTORY */
126 /* */
127 /* DATE NAME DESCRIPTION */
128 /* */
129 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
130 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
131 /* resulting in version 6.1 */
132 /* */
133 /**************************************************************************/
_nx_md5_initialize(NX_MD5 * context)134 UINT _nx_md5_initialize(NX_MD5 *context)
135 {
136
137 /* Determine if the context is non-null. */
138 if (context == NX_NULL)
139 return(NX_PTR_ERROR);
140
141 /* First, clear the bit count for this context. */
142 context -> nx_md5_bit_count[0] = 0; /* Clear the lower 32-bits of the count */
143 context -> nx_md5_bit_count[1] = 0; /* Clear the upper 32-bits of the count */
144
145 /* Finally, setup the context states. */
146 context -> nx_md5_states[0] = 0x67452301UL; /* Setup state A */
147 context -> nx_md5_states[1] = 0xEFCDAB89UL; /* Setup state B */
148 context -> nx_md5_states[2] = 0x98BADCFEUL; /* Setup state C */
149 context -> nx_md5_states[3] = 0x10325476UL; /* Setup state D */
150
151 /* Return success. */
152 return(NX_SUCCESS);
153 }
154
155
156 /**************************************************************************/
157 /* */
158 /* FUNCTION RELEASE */
159 /* */
160 /* _nx_md5_update PORTABLE C */
161 /* 6.1 */
162 /* AUTHOR */
163 /* */
164 /* Yuxin Zhou, Microsoft Corporation */
165 /* */
166 /* DESCRIPTION */
167 /* */
168 /* This function updates the digest calculation with new input from */
169 /* the caller. */
170 /* */
171 /* INPUT */
172 /* */
173 /* context MD5 context pointer */
174 /* input_ptr Pointer to byte(s) of input */
175 /* input_length Length of bytes of input */
176 /* */
177 /* OUTPUT */
178 /* */
179 /* status Completion status */
180 /* */
181 /* CALLS */
182 /* */
183 /* _nx_md5_process_buffer Process complete buffer, */
184 /* which is 64-bytes in size */
185 /* */
186 /* CALLED BY */
187 /* */
188 /* NetX Applications */
189 /* */
190 /* RELEASE HISTORY */
191 /* */
192 /* DATE NAME DESCRIPTION */
193 /* */
194 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
195 /* 09-30-2020 Yuxin Zhou Modified comment(s), and */
196 /* verified memcpy use cases, */
197 /* resulting in version 6.1 */
198 /* */
199 /**************************************************************************/
_nx_md5_update(NX_MD5 * context,UCHAR * input_ptr,UINT input_length)200 UINT _nx_md5_update(NX_MD5 *context, UCHAR *input_ptr, UINT input_length)
201 {
202
203 ULONG current_bytes;
204 ULONG needed_fill_bytes;
205
206
207 /* Determine if the context is non-null. */
208 if (context == NX_NULL)
209 return(NX_PTR_ERROR);
210
211 /* Determine if there is a length. */
212 if (input_length == 0)
213 return(NX_SUCCESS);
214
215 /* Calculate the current byte count mod 64. Note the reason for the
216 shift by 3 is to account for the 8 bits per byte. */
217 current_bytes = (context -> nx_md5_bit_count[0] >> 3) & 0x3F;
218
219 /* Calculate the current number of bytes needed to be filled. */
220 needed_fill_bytes = 64 - current_bytes;
221
222 /* Update the total bit count based on the input length. */
223 context -> nx_md5_bit_count[0] += (input_length << 3);
224
225 /* Determine if there is roll-over of the bit count into the MSW. */
226 if (context -> nx_md5_bit_count[0] < (input_length << 3))
227 {
228
229 /* Yes, increment the MSW of the bit count. */
230 context -> nx_md5_bit_count[1]++;
231 }
232
233 /* Update upper total bit count word. */
234 context -> nx_md5_bit_count[1] += (input_length >> 29);
235
236 /* Check for a partial buffer that needs to be transformed. */
237 if ((current_bytes) && (input_length >= needed_fill_bytes))
238 {
239
240 /* Yes, we can complete the buffer and transform it. */
241
242 /* Copy the appropriate portion of the input buffer into the internal
243 buffer of the context. */
244 memcpy((void *) &(context -> nx_md5_buffer[current_bytes]), (void *) input_ptr, needed_fill_bytes); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
245
246 /* Process the 64-byte (512 bit) buffer. */
247 _nx_md5_process_buffer(context, context -> nx_md5_buffer);
248
249 /* Adjust the pointers and length accordingly. */
250 input_length = input_length - needed_fill_bytes;
251 input_ptr = input_ptr + needed_fill_bytes;
252
253 /* Clear the remaining bits, since the buffer was processed. */
254 current_bytes = 0;
255 }
256
257 /* Process any and all whole blocks of input. */
258 while (input_length >= 64)
259 {
260
261 /* Process this 64-byte (512 bit) buffer. */
262 _nx_md5_process_buffer(context, input_ptr);
263
264 /* Adjust the pointers and length accordingly. */
265 input_length = input_length - 64;
266 input_ptr = input_ptr + 64;
267 }
268
269 /* Determine if there is anything left. */
270 if (input_length)
271 {
272
273 /* Save the remaining bytes in the internal buffer after any remaining bytes
274 that it is processed later. */
275 memcpy((void *) &(context -> nx_md5_buffer[current_bytes]), (void *) input_ptr, input_length); /* Use case of memcpy is verified. lgtm[cpp/banned-api-usage-required-any] */
276 }
277
278 /* Return success. */
279 return(NX_SUCCESS);
280 }
281
282
283 /**************************************************************************/
284 /* */
285 /* FUNCTION RELEASE */
286 /* */
287 /* _nx_md5_digest_calculate PORTABLE C */
288 /* 6.1 */
289 /* AUTHOR */
290 /* */
291 /* Yuxin Zhou, Microsoft Corporation */
292 /* */
293 /* DESCRIPTION */
294 /* */
295 /* This function finishes calculation of the MD5 digest. It is called */
296 /* where there is no further input needed for the digest. The resulting*/
297 /* 16-byte (128-bit) MD5 digest is returned to the caller. */
298 /* */
299 /* INPUT */
300 /* */
301 /* context MD5 context pointer */
302 /* digest 16-byte (128-bit) digest */
303 /* */
304 /* OUTPUT */
305 /* */
306 /* status Completion status */
307 /* */
308 /* CALLS */
309 /* */
310 /* _nx_md5_update Update the digest with padding*/
311 /* and length of digest */
312 /* */
313 /* CALLED BY */
314 /* */
315 /* NetX Applications */
316 /* */
317 /* RELEASE HISTORY */
318 /* */
319 /* DATE NAME DESCRIPTION */
320 /* */
321 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
322 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
323 /* resulting in version 6.1 */
324 /* */
325 /**************************************************************************/
_nx_md5_digest_calculate(NX_MD5 * context,UCHAR digest[16])326 UINT _nx_md5_digest_calculate(NX_MD5 *context, UCHAR digest[16])
327 {
328
329 UCHAR bit_count_string[8];
330 ULONG current_byte_count;
331 ULONG padding_bytes;
332
333
334 /* Move the lower portion of the bit count into the array. */
335 bit_count_string[0] = (UCHAR) context -> nx_md5_bit_count[0];
336 bit_count_string[1] = (UCHAR) (context -> nx_md5_bit_count[0] >> 8);
337 bit_count_string[2] = (UCHAR) (context -> nx_md5_bit_count[0] >> 16);
338 bit_count_string[3] = (UCHAR) (context -> nx_md5_bit_count[0] >> 24);
339 bit_count_string[4] = (UCHAR) context -> nx_md5_bit_count[1];
340 bit_count_string[5] = (UCHAR) (context -> nx_md5_bit_count[1] >> 8);
341 bit_count_string[6] = (UCHAR) (context -> nx_md5_bit_count[1] >> 16);
342 bit_count_string[7] = (UCHAR) (context -> nx_md5_bit_count[1] >> 24);
343
344 /* Calculate the current byte count. */
345 current_byte_count = (context -> nx_md5_bit_count[0] >> 3) & 0x3F;
346
347 /* Calculate the padding bytes needed. */
348 padding_bytes = (current_byte_count < 56) ? (56 - current_byte_count) : (120 - current_byte_count);
349
350 /* Add any padding required. */
351 _nx_md5_update(context, _nx_md5_padding, padding_bytes);
352
353 /* Add the in the length. */
354 _nx_md5_update(context, bit_count_string, 8);
355
356 /* Now store the digest in the caller specified destination. */
357 digest[ 0] = (UCHAR) context -> nx_md5_states[0];
358 digest[ 1] = (UCHAR) (context -> nx_md5_states[0] >> 8);
359 digest[ 2] = (UCHAR) (context -> nx_md5_states[0] >> 16);
360 digest[ 3] = (UCHAR) (context -> nx_md5_states[0] >> 24);
361 digest[ 4] = (UCHAR) context -> nx_md5_states[1];
362 digest[ 5] = (UCHAR) (context -> nx_md5_states[1] >> 8);
363 digest[ 6] = (UCHAR) (context -> nx_md5_states[1] >> 16);
364 digest[ 7] = (UCHAR) (context -> nx_md5_states[1] >> 24);
365 digest[ 8] = (UCHAR) context -> nx_md5_states[2];
366 digest[ 9] = (UCHAR) (context -> nx_md5_states[2] >> 8);
367 digest[10] = (UCHAR) (context -> nx_md5_states[2] >> 16);
368 digest[11] = (UCHAR) (context -> nx_md5_states[2] >> 24);
369 digest[12] = (UCHAR) context -> nx_md5_states[3];
370 digest[13] = (UCHAR) (context -> nx_md5_states[3] >> 8);
371 digest[14] = (UCHAR) (context -> nx_md5_states[3] >> 16);
372 digest[15] = (UCHAR) (context -> nx_md5_states[3] >> 24);
373
374 /* Return successful completion. */
375 return(NX_SUCCESS);
376 }
377
378
379
380 /**************************************************************************/
381 /* */
382 /* FUNCTION RELEASE */
383 /* */
384 /* _nx_md5_process_buffer PORTABLE C */
385 /* 6.1 */
386 /* AUTHOR */
387 /* */
388 /* Yuxin Zhou, Microsoft Corporation */
389 /* */
390 /* DESCRIPTION */
391 /* */
392 /* This function actually uses the MD5 algorithm to process a 64-byte */
393 /* (512 bit) buffer. */
394 /* */
395 /* INPUT */
396 /* */
397 /* context MD5 context pointer */
398 /* buffer 64-byte buffer */
399 /* */
400 /* OUTPUT */
401 /* */
402 /* None */
403 /* */
404 /* CALLS */
405 /* */
406 /* None */
407 /* */
408 /* CALLED BY */
409 /* */
410 /* NetX Applications */
411 /* */
412 /* RELEASE HISTORY */
413 /* */
414 /* DATE NAME DESCRIPTION */
415 /* */
416 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
417 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
418 /* resulting in version 6.1 */
419 /* */
420 /**************************************************************************/
_nx_md5_process_buffer(NX_MD5 * context,UCHAR buffer[64])421 VOID _nx_md5_process_buffer(NX_MD5 *context, UCHAR buffer[64])
422 {
423
424 UINT i, j;
425 ULONG a, b, c, d;
426 ULONG x[16];
427
428
429 /* Initialize the state variables. */
430 a = context -> nx_md5_states[0];
431 b = context -> nx_md5_states[1];
432 c = context -> nx_md5_states[2];
433 d = context -> nx_md5_states[3];
434
435 /* Now, setup the x array of ULONGs for fast processing. */
436 j = 0;
437 for (i = 0; i < 16; i++)
438 {
439
440 /* Convert 4 bytes into one 32-bit word. */
441 x[i] = ((ULONG) buffer[j]) | (((ULONG) buffer[j+1]) << 8) | (((ULONG) buffer[j+2]) << 16) | (((ULONG) buffer[j+3]) << 24);
442
443 /* Move to next position in source array. */
444 j = j + 4;
445 }
446
447 /* Process Round 1 of MD5 calculation. */
448 FF(a, b, c, d, x[ 0], 7, 0xd76aa478UL);
449 FF(d, a, b, c, x[ 1], 12, 0xe8c7b756UL);
450 FF(c, d, a, b, x[ 2], 17, 0x242070dbUL);
451 FF(b, c, d, a, x[ 3], 22, 0xc1bdceeeUL);
452 FF(a, b, c, d, x[ 4], 7, 0xf57c0fafUL);
453 FF(d, a, b, c, x[ 5], 12, 0x4787c62aUL);
454 FF(c, d, a, b, x[ 6], 17, 0xa8304613UL);
455 FF(b, c, d, a, x[ 7], 22, 0xfd469501UL);
456 FF(a, b, c, d, x[ 8], 7, 0x698098d8UL);
457 FF(d, a, b, c, x[ 9], 12, 0x8b44f7afUL);
458 FF(c, d, a, b, x[10], 17, 0xffff5bb1UL);
459 FF(b, c, d, a, x[11], 22, 0x895cd7beUL);
460 FF(a, b, c, d, x[12], 7, 0x6b901122UL);
461 FF(d, a, b, c, x[13], 12, 0xfd987193UL);
462 FF(c, d, a, b, x[14], 17, 0xa679438eUL);
463 FF(b, c, d, a, x[15], 22, 0x49b40821UL);
464
465 /* Process Round 2 of MD5 calculation. */
466 GG(a, b, c, d, x[ 1], 5, 0xf61e2562UL);
467 GG(d, a, b, c, x[ 6], 9, 0xc040b340UL);
468 GG(c, d, a, b, x[11], 14, 0x265e5a51UL);
469 GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aaUL);
470 GG(a, b, c, d, x[ 5], 5, 0xd62f105dUL);
471 GG(d, a, b, c, x[10], 9, 0x02441453UL);
472 GG(c, d, a, b, x[15], 14, 0xd8a1e681UL);
473 GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8UL);
474 GG(a, b, c, d, x[ 9], 5, 0x21e1cde6UL);
475 GG(d, a, b, c, x[14], 9, 0xc33707d6UL);
476 GG(c, d, a, b, x[ 3], 14, 0xf4d50d87UL);
477 GG(b, c, d, a, x[ 8], 20, 0x455a14edUL);
478 GG(a, b, c, d, x[13], 5, 0xa9e3e905UL);
479 GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8UL);
480 GG(c, d, a, b, x[ 7], 14, 0x676f02d9UL);
481 GG(b, c, d, a, x[12], 20, 0x8d2a4c8aUL);
482
483 /* Process Round 3 of MD5 calculation. */
484 HH(a, b, c, d, x[ 5], 4, 0xfffa3942UL);
485 HH(d, a, b, c, x[ 8], 11, 0x8771f681UL);
486 HH(c, d, a, b, x[11], 16, 0x6d9d6122UL);
487 HH(b, c, d, a, x[14], 23, 0xfde5380cUL);
488 HH(a, b, c, d, x[ 1], 4, 0xa4beea44UL);
489 HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9UL);
490 HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60UL);
491 HH(b, c, d, a, x[10], 23, 0xbebfbc70UL);
492 HH(a, b, c, d, x[13], 4, 0x289b7ec6UL);
493 HH(d, a, b, c, x[ 0], 11, 0xeaa127faUL);
494 HH(c, d, a, b, x[ 3], 16, 0xd4ef3085UL);
495 HH(b, c, d, a, x[ 6], 23, 0x04881d05UL);
496 HH(a, b, c, d, x[ 9], 4, 0xd9d4d039UL);
497 HH(d, a, b, c, x[12], 11, 0xe6db99e5UL);
498 HH(c, d, a, b, x[15], 16, 0x1fa27cf8UL);
499 HH(b, c, d, a, x[ 2], 23, 0xc4ac5665UL);
500
501 /* Process Round 4 of MD5 calculation. */
502 II(a, b, c, d, x[ 0], 6, 0xf4292244UL);
503 II(d, a, b, c, x[ 7], 10, 0x432aff97UL);
504 II(c, d, a, b, x[14], 15, 0xab9423a7UL);
505 II(b, c, d, a, x[ 5], 21, 0xfc93a039UL);
506 II(a, b, c, d, x[12], 6, 0x655b59c3UL);
507 II(d, a, b, c, x[ 3], 10, 0x8f0ccc92UL);
508 II(c, d, a, b, x[10], 15, 0xffeff47dUL);
509 II(b, c, d, a, x[ 1], 21, 0x85845dd1UL);
510 II(a, b, c, d, x[ 8], 6, 0x6fa87e4fUL);
511 II(d, a, b, c, x[15], 10, 0xfe2ce6e0UL);
512 II(c, d, a, b, x[ 6], 15, 0xa3014314UL);
513 II(b, c, d, a, x[13], 21, 0x4e0811a1UL);
514 II(a, b, c, d, x[ 4], 6, 0xf7537e82UL);
515 II(d, a, b, c, x[11], 10, 0xbd3af235UL);
516 II(c, d, a, b, x[ 2], 15, 0x2ad7d2bbUL);
517 II(b, c, d, a, x[ 9], 21, 0xeb86d391UL);
518
519 /* Save the resulting in this MD5 context. */
520 context -> nx_md5_states[0] += a;
521 context -> nx_md5_states[1] += b;
522 context -> nx_md5_states[2] += c;
523 context -> nx_md5_states[3] += d;
524 }
525
526