ecere/sys/JSON: Fixed (de)serializing properties using base 'Container' class
[sdk] / extras / md5.ec
1 /*
2  * md5.ec -- An eC adaptation of Alexander Peslyak public domain MD5 implementation
3  * --------------------------------------------------------------------------------
4  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
5  * MD5 Message-Digest Algorithm (RFC 1321).
6  *
7  * Homepage:
8  * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
9  *
10  * Author:
11  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
12  *
13  * This software was written by Alexander Peslyak in 2001.  No copyright is
14  * claimed, and the software is hereby placed in the public domain.
15  * In case this attempt to disclaim copyright and place the software in the
16  * public domain is deemed null and void, then the software is
17  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
18  * general public under the following terms:
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted.
22  *
23  * There's ABSOLUTELY NO WARRANTY, express or implied.
24  *
25  * (This is a heavily cut-down "BSD license".)
26  *
27  * This differs from Colin Plumb's older public domain implementation in that
28  * no exactly 32-bit integer data type is required (any 32-bit or wider
29  * unsigned integer data type will do), there's no compile-time endianness
30  * configuration, and the function prototypes match OpenSSL's.  No code from
31  * Colin Plumb's implementation has been reused; this comment merely compares
32  * the properties of the two independent implementations.
33  *
34  * The primary goals of this implementation are portability and ease of use.
35  * It is meant to be fast, but not as fast as possible.  Some known
36  * optimizations are not included to reduce source code size and avoid
37  * compile-time configuration.
38  */
39
40 struct MD5_CTX
41 {
42    uint32 lo, hi;
43    uint32 a, b, c, d;
44    byte buffer[64];
45    uint32 block[16];
46 } MD5_CTX;
47
48 /*
49  * The basic MD5 functions.
50  *
51  * F and G are optimized compared to their RFC 1321 definitions for
52  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
53  * implementation.
54  */
55 #define F(x, y, z)         ((z) ^ ((x) & ((y) ^ (z))))
56 #define G(x, y, z)         ((y) ^ ((z) & ((x) ^ (y))))
57 #define H(x, y, z)         (((x) ^ (y)) ^ (z))
58 #define H2(x, y, z)        ((x) ^ ((y) ^ (z)))
59 #define I(x, y, z)         ((y) ^ ((x) | ~(z)))
60
61 /*
62  * The MD5 transformation for all four rounds.
63  */
64 #define STEP(f, a, b, c, d, x, t, s) \
65    (a) += f((b), (c), (d)) + (x) + (t); \
66    (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
67    (a) += (b);
68
69 /*
70  * SET reads 4 input bytes in little-endian byte order and stores them
71  * in a properly aligned word in host byte order.
72  *
73  * The check for little-endian architectures that tolerate unaligned
74  * memory accesses is just an optimization.  Nothing will break if it
75  * doesn't work.
76  */
77 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
78 #  define SET(n) (*(uint32 *)&ptr[(n) * 4])
79 #  define GET(n) SET(n)
80 #else
81 #  define SET(n) \
82       (ctx.block[(n)] = \
83       (uint32)ptr[(n) * 4] | \
84       ((uint32)ptr[(n) * 4 + 1] << 8) | \
85       ((uint32)ptr[(n) * 4 + 2] << 16) | \
86       ((uint32)ptr[(n) * 4 + 3] << 24))
87 #  define GET(n) (ctx.block[(n)])
88 #endif
89
90 /*
91  * This processes one or more 64-byte data blocks, but does NOT update
92  * the bit counters.  There are no alignment requirements.
93  */
94 static const void *body(MD5_CTX ctx, const void *data, uint size)
95 {
96    const byte *ptr = (const byte *)data;
97    uint32 a = ctx.a, b = ctx.b, c = ctx.c, d = ctx.d;
98    do
99    {
100       uint32 saved_a = a, saved_b = b, saved_c = c, saved_d = d;
101
102       // Round 1
103       STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
104       STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
105       STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
106       STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
107       STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
108       STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
109       STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
110       STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
111       STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
112       STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
113       STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
114       STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
115       STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
116       STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
117       STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
118       STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
119
120       // Round 2
121       STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
122       STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
123       STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
124       STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
125       STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
126       STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
127       STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
128       STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
129       STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
130       STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
131       STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
132       STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
133       STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
134       STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
135       STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
136       STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
137
138       // Round 3
139       STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
140       STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
141       STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
142       STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
143       STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
144       STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
145       STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
146       STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
147       STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
148       STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
149       STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
150       STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
151       STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
152       STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
153       STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
154       STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
155
156       // Round 4
157       STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
158       STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
159       STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
160       STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
161       STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
162       STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
163       STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
164       STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
165       STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
166       STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
167       STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
168       STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
169       STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
170       STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
171       STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
172       STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
173
174       a += saved_a;
175       b += saved_b;
176       c += saved_c;
177       d += saved_d;
178
179       ptr += 64;
180    } while (size -= 64);
181
182    ctx.a = a;
183    ctx.b = b;
184    ctx.c = c;
185    ctx.d = d;
186
187    return ptr;
188 }
189
190 void MD5Init(MD5_CTX ctx)
191 {
192    ctx =
193    {
194       a = 0x67452301;
195       b = 0xefcdab89;
196       c = 0x98badcfe;
197       d = 0x10325476;
198    };
199 }
200
201 void MD5Update(MD5_CTX ctx, const byte *data, uint size)
202 {
203    uint32 saved_lo = ctx.lo;
204    uint used = saved_lo & 0x3f;
205
206    if((ctx.lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
207       ctx.hi++;
208    ctx.hi += size >> 29;
209
210    if(used)
211    {
212       uint available = 64 - used;
213
214       if(size < available)
215       {
216          memcpy(&ctx.buffer[used], data, size);
217          return;
218       }
219
220       memcpy(&ctx.buffer[used], data, available);
221       data = (const byte *)data + available;
222       size -= available;
223       body(ctx, ctx.buffer, 64);
224    }
225
226    if(size >= 64)
227    {
228       data = body(ctx, data, size & ~(uint)0x3f);
229       size &= 0x3f;
230    }
231
232    memcpy(ctx.buffer, data, size);
233 }
234
235 void MD5Final(byte *result, MD5_CTX ctx)
236 {
237    uint used = ctx.lo & 0x3f;
238    uint available = 64 - used;
239
240    ctx.buffer[used++] = 0x80;
241
242    if(available < 8)
243    {
244       memset(&ctx.buffer[used], 0, available);
245       body(ctx, ctx.buffer, 64);
246       used = 0;
247       available = 64;
248    }
249
250    memset(&ctx.buffer[used], 0, available - 8);
251
252    ctx.lo <<= 3;
253    ctx.buffer[56] = (byte)ctx.lo;
254    ctx.buffer[57] = ctx.lo >> 8;
255    ctx.buffer[58] = ctx.lo >> 16;
256    ctx.buffer[59] = ctx.lo >> 24;
257    ctx.buffer[60] = (byte)ctx.hi;
258    ctx.buffer[61] = ctx.hi >> 8;
259    ctx.buffer[62] = ctx.hi >> 16;
260    ctx.buffer[63] = ctx.hi >> 24;
261
262    body(ctx, ctx.buffer, 64);
263
264    result[0] = (byte)ctx.a;
265    result[1] = ctx.a >> 8;
266    result[2] = ctx.a >> 16;
267    result[3] = ctx.a >> 24;
268    result[4] = (byte)ctx.b;
269    result[5] = ctx.b >> 8;
270    result[6] = ctx.b >> 16;
271    result[7] = ctx.b >> 24;
272    result[8] = (byte)ctx.c;
273    result[9] = ctx.c >> 8;
274    result[10] = ctx.c >> 16;
275    result[11] = ctx.c >> 24;
276    result[12] = (byte)ctx.d;
277    result[13] = ctx.d >> 8;
278    result[14] = ctx.d >> 16;
279    result[15] = ctx.d >> 24;
280
281    memset(ctx, 0, sizeof(MD5_CTX));
282 }
283
284 void MD5Digest(const char * string, int len, char * output)
285 {
286    byte bytes[16];
287    int c;
288    MD5_CTX ctx;
289    MD5Init(&ctx);
290    MD5Update(&ctx, (byte *)string, len);
291    MD5Final(bytes, &ctx);
292    len = 0;
293    for(c = 0; c<16; c++)
294    {
295       sprintf(output + len, "%02x", bytes[c]);
296       len += 2;
297    }
298 }
299
300 void MD5Digest64(const char * string, int len, uint64 * output)
301 {
302    byte bytes[16];
303    MD5_CTX ctx;
304    MD5Init(&ctx);
305    MD5Update(&ctx, (byte *)string, len);
306    MD5Final(bytes, &ctx);
307    output[0] = ((uint64)bytes[ 0] << 56) | ((uint64)bytes[ 1] << 48) | ((uint64)bytes[ 2] << 40) | ((uint64)bytes[ 3] << 32) |
308                ((uint64)bytes[ 4] << 24) | ((uint64)bytes[ 5] << 16) | ((uint64)bytes[ 6] <<  8) | ((uint64)bytes[ 7]      );
309    output[1] = ((uint64)bytes[ 8] << 56) | ((uint64)bytes[ 9] << 48) | ((uint64)bytes[10] << 40) | ((uint64)bytes[11] << 32) |
310                ((uint64)bytes[12] << 24) | ((uint64)bytes[13] << 16) | ((uint64)bytes[14] <<  8) | ((uint64)bytes[15]      );
311 }