]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_md5.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_md5.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 /*
28  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
29  * MD5 Message-Digest Algorithm (RFC 1321).
30  *
31  * Homepage:
32  * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
33  *
34  * Author:
35  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
36  *
37  * This software was written by Alexander Peslyak in 2001.  No copyright is
38  * claimed, and the software is hereby placed in the public domain.
39  * In case this attempt to disclaim copyright and place the software in the
40  * public domain is deemed null and void, then the software is
41  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
42  * general public under the following terms:
43  *
44  * Redistribution and use in source and binary forms, with or without
45  * modification, are permitted.
46  *
47  * There's ABSOLUTELY NO WARRANTY, express or implied.
48  *
49  * (This is a heavily cut-down "BSD license".)
50  *
51  * This differs from Colin Plumb's older public domain implementation in that
52  * no exactly 32-bit integer data type is required (any 32-bit or wider
53  * unsigned integer data type will do), there's no compile-time endianness
54  * configuration, and the function prototypes match OpenSSL's.  No code from
55  * Colin Plumb's implementation has been reused; this comment merely compares
56  * the properties of the two independent implementations.
57  *
58  * The primary goals of this implementation are portability and ease of use.
59  * It is meant to be fast, but not as fast as possible.  Some known
60  * optimizations are not included to reduce source code size and avoid
61  * compile-time configuration.
62  */
63
64 #include <string.h>
65
66 #include "vogl_md5.h"
67
68 namespace vogl
69 {
70
71 /*
72  * The basic MD5 functions.
73  *
74  * F and G are optimized compared to their RFC 1321 definitions for
75  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
76  * implementation.
77  */
78 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
79 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
80 #define H(x, y, z) ((x) ^ (y) ^ (z))
81 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
82
83 /*
84  * The MD5 transformation for all four rounds.
85  */
86 #define STEP(f, a, b, c, d, x, t, s)                           \
87     (a) += f((b), (c), (d)) + (x) + (t);                       \
88     (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
89     (a) += (b);
90
91 /*
92  * SET reads 4 input bytes in little-endian byte order and stores them
93  * in a properly aligned word in host byte order.
94  *
95  * The check for little-endian architectures that tolerate unaligned
96  * memory accesses is just an optimization.  Nothing will break if it
97  * doesn't work.
98  */
99 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
100 #define SET(n) \
101     (*(MD5_u32plus *)&ptr[(n) * 4])
102 #define GET(n) \
103     SET(n)
104 #else
105 #define SET(n)                                   \
106     (ctx->block[(n)] =                           \
107          (MD5_u32plus)ptr[(n) * 4] |             \
108          ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) |  \
109          ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
110          ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
111 #define GET(n) \
112     (ctx->block[(n)])
113 #endif
114
115     /*
116  * This processes one or more 64-byte data blocks, but does NOT update
117  * the bit counters.  There are no alignment requirements.
118  */
119     static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
120     {
121         const unsigned char *ptr;
122         MD5_u32plus a, b, c, d;
123         MD5_u32plus saved_a, saved_b, saved_c, saved_d;
124
125         ptr = static_cast<const unsigned char *>(data);
126
127         a = ctx->a;
128         b = ctx->b;
129         c = ctx->c;
130         d = ctx->d;
131
132         do
133         {
134             saved_a = a;
135             saved_b = b;
136             saved_c = c;
137             saved_d = d;
138
139             /* Round 1 */
140             STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
141             STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
142             STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
143             STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
144             STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
145             STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
146             STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
147             STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
148             STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
149             STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
150             STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
151             STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
152             STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
153             STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
154             STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
155             STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
156
157             /* Round 2 */
158             STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
159             STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
160             STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
161             STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
162             STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
163             STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
164             STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
165             STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
166             STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
167             STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
168             STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
169             STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
170             STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
171             STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
172             STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
173             STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
174
175             /* Round 3 */
176             STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
177             STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
178             STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
179             STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
180             STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
181             STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
182             STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
183             STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
184             STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
185             STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
186             STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
187             STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
188             STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
189             STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
190             STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
191             STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
192
193             /* Round 4 */
194             STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
195             STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
196             STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
197             STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
198             STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
199             STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
200             STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
201             STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
202             STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
203             STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
204             STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
205             STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
206             STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
207             STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
208             STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
209             STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
210
211             a += saved_a;
212             b += saved_b;
213             c += saved_c;
214             d += saved_d;
215
216             ptr += 64;
217         } while (size -= 64);
218
219         ctx->a = a;
220         ctx->b = b;
221         ctx->c = c;
222         ctx->d = d;
223
224         return ptr;
225     }
226
227     void MD5_Init(MD5_CTX *ctx)
228     {
229         ctx->a = 0x67452301;
230         ctx->b = 0xefcdab89;
231         ctx->c = 0x98badcfe;
232         ctx->d = 0x10325476;
233
234         ctx->lo = 0;
235         ctx->hi = 0;
236     }
237
238     void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
239     {
240         MD5_u32plus saved_lo;
241         unsigned long used, free;
242
243         saved_lo = ctx->lo;
244         if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
245             ctx->hi++;
246         ctx->hi += size >> 29;
247
248         used = saved_lo & 0x3f;
249
250         if (used)
251         {
252             free = 64 - used;
253
254             if (size < free)
255             {
256                 memcpy(&ctx->buffer[used], data, size);
257                 return;
258             }
259
260             memcpy(&ctx->buffer[used], data, free);
261             data = (unsigned char *)data + free;
262             size -= free;
263             body(ctx, ctx->buffer, 64);
264         }
265
266         if (size >= 64)
267         {
268             data = body(ctx, data, size & ~(unsigned long)0x3f);
269             size &= 0x3f;
270         }
271
272         memcpy(ctx->buffer, data, size);
273     }
274
275     void MD5_Final(unsigned char *result, MD5_CTX *ctx)
276     {
277         unsigned long used, free;
278
279         used = ctx->lo & 0x3f;
280
281         ctx->buffer[used++] = 0x80;
282
283         free = 64 - used;
284
285         if (free < 8)
286         {
287             memset(&ctx->buffer[used], 0, free);
288             body(ctx, ctx->buffer, 64);
289             used = 0;
290             free = 64;
291         }
292
293         memset(&ctx->buffer[used], 0, free - 8);
294
295         ctx->lo <<= 3;
296         ctx->buffer[56] = ctx->lo;
297         ctx->buffer[57] = ctx->lo >> 8;
298         ctx->buffer[58] = ctx->lo >> 16;
299         ctx->buffer[59] = ctx->lo >> 24;
300         ctx->buffer[60] = ctx->hi;
301         ctx->buffer[61] = ctx->hi >> 8;
302         ctx->buffer[62] = ctx->hi >> 16;
303         ctx->buffer[63] = ctx->hi >> 24;
304
305         body(ctx, ctx->buffer, 64);
306
307         result[0] = ctx->a;
308         result[1] = ctx->a >> 8;
309         result[2] = ctx->a >> 16;
310         result[3] = ctx->a >> 24;
311         result[4] = ctx->b;
312         result[5] = ctx->b >> 8;
313         result[6] = ctx->b >> 16;
314         result[7] = ctx->b >> 24;
315         result[8] = ctx->c;
316         result[9] = ctx->c >> 8;
317         result[10] = ctx->c >> 16;
318         result[11] = ctx->c >> 24;
319         result[12] = ctx->d;
320         result[13] = ctx->d >> 8;
321         result[14] = ctx->d >> 16;
322         result[15] = ctx->d >> 24;
323
324         memset(ctx, 0, sizeof(*ctx));
325     }
326
327     // Result needs to be directly extracted by the caller from ctx.a, ctx.b, etc. and the context is not cleared for perf.
328     void MD5_Final(MD5_CTX *ctx)
329     {
330         unsigned long used, free;
331
332         used = ctx->lo & 0x3f;
333
334         ctx->buffer[used++] = 0x80;
335
336         free = 64 - used;
337
338         if (free < 8)
339         {
340             memset(&ctx->buffer[used], 0, free);
341             body(ctx, ctx->buffer, 64);
342             used = 0;
343             free = 64;
344         }
345
346         memset(&ctx->buffer[used], 0, free - 8);
347
348         ctx->lo <<= 3;
349         ctx->buffer[56] = ctx->lo;
350         ctx->buffer[57] = ctx->lo >> 8;
351         ctx->buffer[58] = ctx->lo >> 16;
352         ctx->buffer[59] = ctx->lo >> 24;
353         ctx->buffer[60] = ctx->hi;
354         ctx->buffer[61] = ctx->hi >> 8;
355         ctx->buffer[62] = ctx->hi >> 16;
356         ctx->buffer[63] = ctx->hi >> 24;
357
358         body(ctx, ctx->buffer, 64);
359     }
360
361     bool md5_test()
362     {
363         md5_hash_gen gen;
364
365         gen.update("The quick brown fox jumps over the lazy dog");
366         if (gen.finalize() != md5_hash(0x9D7D109E, 0x82B62B37, 0x351DD86B, 0xD619A442))
367             return false;
368
369         gen.clear();
370         gen.update("The quick brown fox jumps over the lazy dog.");
371         if (gen.finalize() != md5_hash(0xC209D9E4, 0x1CFBD090, 0xADFF68A0, 0xD0CB22DF))
372             return false;
373
374         gen.clear();
375         gen.update("This is a test");
376         if (gen.finalize() != md5_hash("ce114e4501d2f4e2dcea3e17b546f339"))
377             return false;
378
379         gen.clear();
380         gen.update("A");
381         if (gen.finalize() != md5_hash("7fc56270e7a70fa81a5935b72eacbe29"))
382             return false;
383         gen.update("B");
384         if (gen.finalize() != md5_hash("b86fc6b051f63d73de262d4c34e3a0a9"))
385             return false;
386         gen.update("C");
387         if (gen.finalize() != md5_hash("902fbdd2b1df0c4f70b4a5d23525e932"))
388             return false;
389
390         dynamic_string str;
391         gen.finalize().get_string(str);
392         if (str != "902fbdd2b1df0c4f70b4a5d23525e932")
393             return false;
394
395         gen.clear();
396         if (gen.finalize() != md5_hash("d41d8cd98f00b204e9800998ecf8427e"))
397             return false;
398         if (!(gen.finalize() == md5_hash("d41d8cd98f00b204e9800998ecf8427e")))
399             return false;
400         if (gen.finalize() < md5_hash("d41d8cd98f00b204e9800998ecf8427e"))
401             return false;
402
403         if (md5_hash_gen("fadsahfuidsyuifeywiurhwekjlrhblekwjhbrkjewqhrkjhewrf89ds7f987dsa897dsf9gyuierhlgkjhrekjthnrkejlthoruioguopdsifuapofsdj'fjdsaklhgkdjslfhgjkdfsgfdhjogiuyfviubygvvcx876bv87xcz6vcxyvcxyhkjv").finalize() != md5_hash("8897731974459964203eeee0851d1ef4"))
404             return false;
405
406         // purposely should fail
407         if (!(md5_hash_gen("Xfadsahfuidsyuifeywiurhwekjlrhblekwjhbrkjewqhrkjhewrf89ds7f987dsa897dsf9gyuierhlgkjhrekjthnrkejlthoruioguopdsifuapofsdj'fjdsaklhgkdjslfhgjkdfsgfdhjogiuyfviubygvvcx876bv87xcz6vcxyvcxyhkjv").finalize() != md5_hash("8897731974459964203eeee0851d1ef4")))
408             return false;
409
410         if (md5_hash_gen("oidui09ds87f87cfudshufhdsfhkdjhfvu9icxyv789cx67v86dsf87ytiudshfiuhgkjrgwekjhreiour098dsu890f7d897f0ds7g8cydoivhckjhbvkjcvxh98v7by896fs785ds86f586tiy342ugr5iug432rdskhfdsiovioxcuyf890sd78fd78sayuhejhrjkehkjhsdjkfndsjvhd89cv7y8c7x96v78d68f76ds78f6ds78f89sd7f8ds7f98ds7087ds896guicxyviuyxhciuvhyxchvkjcxhkvjhcxuiysdfuifg").finalize() != md5_hash("9d641c30f6755515f6d98258cfc1b300"))
411             return false;
412
413         return true;
414     }
415
416 } // namespace vogl