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