1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22/*
23 ***********************************************************************
24 ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
25 ** Created: 2/17/90 RLR **
26 ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
27 ***********************************************************************
28 */
29
30/*
31 ***********************************************************************
32 ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
33 ** **
34 ** License to copy and use this software is granted provided that **
35 ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
36 ** Digest Algorithm" in all material mentioning or referencing this **
37 ** software or this function. **
38 ** **
39 ** License is also granted to make and use derivative works **
40 ** provided that such works are identified as "derived from the RSA **
41 ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
42 ** material mentioning or referencing the derived work. **
43 ** **
44 ** RSA Data Security, Inc. makes no representations concerning **
45 ** either the merchantability of this software or the suitability **
46 ** of this software for any particular purpose. It is provided "as **
47 ** is" without express or implied warranty of any kind. **
48 ** **
49 ** These notices must be retained in any copies of any part of this **
50 ** documentation and/or software. **
51 ***********************************************************************
52 */
53#include <SDL3/SDL_test.h>
54
55/* Forward declaration of static helper function */
56static void SDLTest_Md5Transform(MD5UINT4 *buf, const MD5UINT4 *in);
57
58static unsigned char MD5PADDING[64] = {
59 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
67};
68
69/* F, G, H and I are basic MD5 functions */
70#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
71#define G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
72#define H(x, y, z) ((x) ^ (y) ^ (z))
73#define I(x, y, z) ((y) ^ ((x) | (~(z))))
74
75/* ROTATE_LEFT rotates x left n bits */
76#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
77
78/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
79
80/* Rotation is separate from addition to prevent recomputation */
81#define FF(a, b, c, d, x, s, ac) \
82 { \
83 (a) += F((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
84 (a) = ROTATE_LEFT((a), (s)); \
85 (a) += (b); \
86 }
87#define GG(a, b, c, d, x, s, ac) \
88 { \
89 (a) += G((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
90 (a) = ROTATE_LEFT((a), (s)); \
91 (a) += (b); \
92 }
93#define HH(a, b, c, d, x, s, ac) \
94 { \
95 (a) += H((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
96 (a) = ROTATE_LEFT((a), (s)); \
97 (a) += (b); \
98 }
99#define II(a, b, c, d, x, s, ac) \
100 { \
101 (a) += I((b), (c), (d)) + (x) + (MD5UINT4)(ac); \
102 (a) = ROTATE_LEFT((a), (s)); \
103 (a) += (b); \
104 }
105
106/*
107 The routine MD5Init initializes the message-digest context
108 mdContext. All fields are set to zero.
109*/
110
111void SDLTest_Md5Init(SDLTest_Md5Context *mdContext)
112{
113 if (!mdContext) {
114 return;
115 }
116
117 mdContext->i[0] = mdContext->i[1] = (MD5UINT4)0;
118
119 /*
120 * Load magic initialization constants.
121 */
122 mdContext->buf[0] = (MD5UINT4)0x67452301;
123 mdContext->buf[1] = (MD5UINT4)0xefcdab89;
124 mdContext->buf[2] = (MD5UINT4)0x98badcfe;
125 mdContext->buf[3] = (MD5UINT4)0x10325476;
126}
127
128/*
129 The routine MD5Update updates the message-digest context to
130 account for the presence of each of the characters inBuf[0..inLen-1]
131 in the message whose digest is being computed.
132*/
133
134void SDLTest_Md5Update(SDLTest_Md5Context *mdContext, unsigned char *inBuf,
135 unsigned int inLen)
136{
137 MD5UINT4 in[16];
138 int mdi;
139 unsigned int i, ii;
140
141 if (!mdContext) {
142 return;
143 }
144 if (!inBuf || inLen < 1) {
145 return;
146 }
147
148 /*
149 * compute number of bytes mod 64
150 */
151 mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
152
153 /*
154 * update number of bits
155 */
156 if ((mdContext->i[0] + ((MD5UINT4)inLen << 3)) < mdContext->i[0]) {
157 mdContext->i[1]++;
158 }
159 mdContext->i[0] += ((MD5UINT4)inLen << 3);
160 mdContext->i[1] += ((MD5UINT4)inLen >> 29);
161
162 while (inLen--) {
163 /*
164 * add new character to buffer, increment mdi
165 */
166 mdContext->in[mdi++] = *inBuf++;
167
168 /*
169 * transform if necessary
170 */
171 if (mdi == 0x40) {
172 for (i = 0, ii = 0; i < 16; i++, ii += 4) {
173 in[i] = (((MD5UINT4)mdContext->in[ii + 3]) << 24) | (((MD5UINT4)mdContext->in[ii + 2]) << 16) | (((MD5UINT4)mdContext->in[ii + 1]) << 8) | ((MD5UINT4)mdContext->in[ii]);
174 }
175 SDLTest_Md5Transform(mdContext->buf, in);
176 mdi = 0;
177 }
178 }
179}
180
181/*
182 The routine MD5Final terminates the message-digest computation and
183 ends with the desired message digest in mdContext->digest[0...15].
184*/
185
186void SDLTest_Md5Final(SDLTest_Md5Context *mdContext)
187{
188 MD5UINT4 in[16];
189 int mdi;
190 unsigned int i, ii;
191 unsigned int padLen;
192
193 if (!mdContext) {
194 return;
195 }
196
197 /*
198 * save number of bits
199 */
200 in[14] = mdContext->i[0];
201 in[15] = mdContext->i[1];
202
203 /*
204 * compute number of bytes mod 64
205 */
206 mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
207
208 /*
209 * pad out to 56 mod 64
210 */
211 padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
212 SDLTest_Md5Update(mdContext, MD5PADDING, padLen);
213
214 /*
215 * append length in bits and transform
216 */
217 for (i = 0, ii = 0; i < 14; i++, ii += 4) {
218 in[i] = (((MD5UINT4)mdContext->in[ii + 3]) << 24) | (((MD5UINT4)mdContext->in[ii + 2]) << 16) | (((MD5UINT4)mdContext->in[ii + 1]) << 8) | ((MD5UINT4)mdContext->in[ii]);
219 }
220 SDLTest_Md5Transform(mdContext->buf, in);
221
222 /*
223 * store buffer in digest
224 */
225 for (i = 0, ii = 0; i < 4; i++, ii += 4) {
226 mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
227 mdContext->digest[ii + 1] =
228 (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
229 mdContext->digest[ii + 2] =
230 (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
231 mdContext->digest[ii + 3] =
232 (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
233 }
234}
235
236/* Basic MD5 step. Transforms buf based on in.
237 */
238static void SDLTest_Md5Transform(MD5UINT4 *buf, const MD5UINT4 *in)
239{
240 MD5UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
241
242 /*
243 * Round 1
244 */
245#define S11 7
246#define S12 12
247#define S13 17
248#define S14 22
249 FF(a, b, c, d, in[0], S11, 3614090360u); /* 1 */
250 FF(d, a, b, c, in[1], S12, 3905402710u); /* 2 */
251 FF(c, d, a, b, in[2], S13, 606105819u); /* 3 */
252 FF(b, c, d, a, in[3], S14, 3250441966u); /* 4 */
253 FF(a, b, c, d, in[4], S11, 4118548399u); /* 5 */
254 FF(d, a, b, c, in[5], S12, 1200080426u); /* 6 */
255 FF(c, d, a, b, in[6], S13, 2821735955u); /* 7 */
256 FF(b, c, d, a, in[7], S14, 4249261313u); /* 8 */
257 FF(a, b, c, d, in[8], S11, 1770035416u); /* 9 */
258 FF(d, a, b, c, in[9], S12, 2336552879u); /* 10 */
259 FF(c, d, a, b, in[10], S13, 4294925233u); /* 11 */
260 FF(b, c, d, a, in[11], S14, 2304563134u); /* 12 */
261 FF(a, b, c, d, in[12], S11, 1804603682u); /* 13 */
262 FF(d, a, b, c, in[13], S12, 4254626195u); /* 14 */
263 FF(c, d, a, b, in[14], S13, 2792965006u); /* 15 */
264 FF(b, c, d, a, in[15], S14, 1236535329u); /* 16 */
265
266 /*
267 * Round 2
268 */
269#define S21 5
270#define S22 9
271#define S23 14
272#define S24 20
273 GG(a, b, c, d, in[1], S21, 4129170786u); /* 17 */
274 GG(d, a, b, c, in[6], S22, 3225465664u); /* 18 */
275 GG(c, d, a, b, in[11], S23, 643717713u); /* 19 */
276 GG(b, c, d, a, in[0], S24, 3921069994u); /* 20 */
277 GG(a, b, c, d, in[5], S21, 3593408605u); /* 21 */
278 GG(d, a, b, c, in[10], S22, 38016083u); /* 22 */
279 GG(c, d, a, b, in[15], S23, 3634488961u); /* 23 */
280 GG(b, c, d, a, in[4], S24, 3889429448u); /* 24 */
281 GG(a, b, c, d, in[9], S21, 568446438u); /* 25 */
282 GG(d, a, b, c, in[14], S22, 3275163606u); /* 26 */
283 GG(c, d, a, b, in[3], S23, 4107603335u); /* 27 */
284 GG(b, c, d, a, in[8], S24, 1163531501u); /* 28 */
285 GG(a, b, c, d, in[13], S21, 2850285829u); /* 29 */
286 GG(d, a, b, c, in[2], S22, 4243563512u); /* 30 */
287 GG(c, d, a, b, in[7], S23, 1735328473u); /* 31 */
288 GG(b, c, d, a, in[12], S24, 2368359562u); /* 32 */
289
290 /*
291 * Round 3
292 */
293#define S31 4
294#define S32 11
295#define S33 16
296#define S34 23
297 HH(a, b, c, d, in[5], S31, 4294588738u); /* 33 */
298 HH(d, a, b, c, in[8], S32, 2272392833u); /* 34 */
299 HH(c, d, a, b, in[11], S33, 1839030562u); /* 35 */
300 HH(b, c, d, a, in[14], S34, 4259657740u); /* 36 */
301 HH(a, b, c, d, in[1], S31, 2763975236u); /* 37 */
302 HH(d, a, b, c, in[4], S32, 1272893353u); /* 38 */
303 HH(c, d, a, b, in[7], S33, 4139469664u); /* 39 */
304 HH(b, c, d, a, in[10], S34, 3200236656u); /* 40 */
305 HH(a, b, c, d, in[13], S31, 681279174u); /* 41 */
306 HH(d, a, b, c, in[0], S32, 3936430074u); /* 42 */
307 HH(c, d, a, b, in[3], S33, 3572445317u); /* 43 */
308 HH(b, c, d, a, in[6], S34, 76029189u); /* 44 */
309 HH(a, b, c, d, in[9], S31, 3654602809u); /* 45 */
310 HH(d, a, b, c, in[12], S32, 3873151461u); /* 46 */
311 HH(c, d, a, b, in[15], S33, 530742520u); /* 47 */
312 HH(b, c, d, a, in[2], S34, 3299628645u); /* 48 */
313
314 /*
315 * Round 4
316 */
317#define S41 6
318#define S42 10
319#define S43 15
320#define S44 21
321 II(a, b, c, d, in[0], S41, 4096336452u); /* 49 */
322 II(d, a, b, c, in[7], S42, 1126891415u); /* 50 */
323 II(c, d, a, b, in[14], S43, 2878612391u); /* 51 */
324 II(b, c, d, a, in[5], S44, 4237533241u); /* 52 */
325 II(a, b, c, d, in[12], S41, 1700485571u); /* 53 */
326 II(d, a, b, c, in[3], S42, 2399980690u); /* 54 */
327 II(c, d, a, b, in[10], S43, 4293915773u); /* 55 */
328 II(b, c, d, a, in[1], S44, 2240044497u); /* 56 */
329 II(a, b, c, d, in[8], S41, 1873313359u); /* 57 */
330 II(d, a, b, c, in[15], S42, 4264355552u); /* 58 */
331 II(c, d, a, b, in[6], S43, 2734768916u); /* 59 */
332 II(b, c, d, a, in[13], S44, 1309151649u); /* 60 */
333 II(a, b, c, d, in[4], S41, 4149444226u); /* 61 */
334 II(d, a, b, c, in[11], S42, 3174756917u); /* 62 */
335 II(c, d, a, b, in[2], S43, 718787259u); /* 63 */
336 II(b, c, d, a, in[9], S44, 3951481745u); /* 64 */
337
338 buf[0] += a;
339 buf[1] += b;
340 buf[2] += c;
341 buf[3] += d;
342}
343