blob: 8e50c798498f94ff5df55b23818b8eff825cbe99 [file] [log] [blame]
tanjent@gmail.comf3b78972012-03-01 03:38:55 +00001#include <memory.h>
2#include "Types.h"
3
4// "Derived from the RSA Data Security, Inc. MD5 Message Digest Algorithm"
5
6/**
7 * \brief MD5 context structure
8 */
9typedef struct
10{
11 unsigned long total[2]; /*!< number of bytes processed */
12 unsigned long state[4]; /*!< intermediate digest state */
13 unsigned char buffer[64]; /*!< data block being processed */
14
15 unsigned char ipad[64]; /*!< HMAC: inner padding */
16 unsigned char opad[64]; /*!< HMAC: outer padding */
17}
18md5_context;
19
20/**
21 * \brief MD5 context setup
22 *
23 * \param ctx context to be initialized
24 */
25void md5_starts( md5_context *ctx );
26
27/**
28 * \brief MD5 process buffer
29 *
30 * \param ctx MD5 context
31 * \param input buffer holding the data
32 * \param ilen length of the input data
33 */
34void md5_update( md5_context *ctx, unsigned char *input, int ilen );
35
36/**
37 * \brief MD5 final digest
38 *
39 * \param ctx MD5 context
40 * \param output MD5 checksum result
41 */
42void md5_finish( md5_context *ctx, unsigned char output[16] );
43
44/**
45 * \brief Output = MD5( input buffer )
46 *
47 * \param input buffer holding the data
48 * \param ilen length of the input data
49 * \param output MD5 checksum result
50 */
51void md5( unsigned char *input, int ilen, unsigned char output[16] );
52
53/**
54 * \brief Output = MD5( file contents )
55 *
56 * \param path input file name
57 * \param output MD5 checksum result
58 *
59 * \return 0 if successful, 1 if fopen failed,
60 * or 2 if fread failed
61 */
62int md5_file( char *path, unsigned char output[16] );
63
64/**
65 * \brief MD5 HMAC context setup
66 *
67 * \param ctx HMAC context to be initialized
68 * \param key HMAC secret key
69 * \param keylen length of the HMAC key
70 */
71void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen );
72
73/**
74 * \brief MD5 HMAC process buffer
75 *
76 * \param ctx HMAC context
77 * \param input buffer holding the data
78 * \param ilen length of the input data
79 */
80void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen );
81
82/**
83 * \brief MD5 HMAC final digest
84 *
85 * \param ctx HMAC context
86 * \param output MD5 HMAC checksum result
87 */
88void md5_hmac_finish( md5_context *ctx, unsigned char output[16] );
89
90/**
91 * \brief Output = HMAC-MD5( hmac key, input buffer )
92 *
93 * \param key HMAC secret key
94 * \param keylen length of the HMAC key
95 * \param input buffer holding the data
96 * \param ilen length of the input data
97 * \param output HMAC-MD5 result
98 */
99void md5_hmac( unsigned char *key, int keylen,
100 unsigned char *input, int ilen,
101 unsigned char output[16] );
102
103/**
104 * \brief Checkup routine
105 *
106 * \return 0 if successful, or 1 if the test failed
107 */
108int md5_self_test( int verbose );
109
110/*
111 * 32-bit integer manipulation macros (little endian)
112 */
113#ifndef GET_ULONG_LE
114#define GET_ULONG_LE(n,b,i) \
115{ \
116 (n) = ( (unsigned long) (b)[(i) ] ) \
117 | ( (unsigned long) (b)[(i) + 1] << 8 ) \
118 | ( (unsigned long) (b)[(i) + 2] << 16 ) \
119 | ( (unsigned long) (b)[(i) + 3] << 24 ); \
120}
121#endif
122
123#ifndef PUT_ULONG_LE
124#define PUT_ULONG_LE(n,b,i) \
125{ \
126 (b)[(i) ] = (unsigned char) ( (n) ); \
127 (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
128 (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
129 (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
130}
131#endif
132
133/*
134 * MD5 context setup
135 */
136void md5_starts( md5_context *ctx )
137{
138 ctx->total[0] = 0;
139 ctx->total[1] = 0;
140
141 ctx->state[0] = 0x67452301;
142 ctx->state[1] = 0xEFCDAB89;
143 ctx->state[2] = 0x98BADCFE;
144 ctx->state[3] = 0x10325476;
145}
146
147static void md5_process( md5_context *ctx, unsigned char data[64] )
148{
149 unsigned long X[16], A, B, C, D;
150
151 GET_ULONG_LE( X[ 0], data, 0 );
152 GET_ULONG_LE( X[ 1], data, 4 );
153 GET_ULONG_LE( X[ 2], data, 8 );
154 GET_ULONG_LE( X[ 3], data, 12 );
155 GET_ULONG_LE( X[ 4], data, 16 );
156 GET_ULONG_LE( X[ 5], data, 20 );
157 GET_ULONG_LE( X[ 6], data, 24 );
158 GET_ULONG_LE( X[ 7], data, 28 );
159 GET_ULONG_LE( X[ 8], data, 32 );
160 GET_ULONG_LE( X[ 9], data, 36 );
161 GET_ULONG_LE( X[10], data, 40 );
162 GET_ULONG_LE( X[11], data, 44 );
163 GET_ULONG_LE( X[12], data, 48 );
164 GET_ULONG_LE( X[13], data, 52 );
165 GET_ULONG_LE( X[14], data, 56 );
166 GET_ULONG_LE( X[15], data, 60 );
167
168#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
169
170#define P(a,b,c,d,k,s,t) \
171{ \
172 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
173}
174
175 A = ctx->state[0];
176 B = ctx->state[1];
177 C = ctx->state[2];
178 D = ctx->state[3];
179
180#define F(x,y,z) (z ^ (x & (y ^ z)))
181
182 P( A, B, C, D, 0, 7, 0xD76AA478 );
183 P( D, A, B, C, 1, 12, 0xE8C7B756 );
184 P( C, D, A, B, 2, 17, 0x242070DB );
185 P( B, C, D, A, 3, 22, 0xC1BDCEEE );
186 P( A, B, C, D, 4, 7, 0xF57C0FAF );
187 P( D, A, B, C, 5, 12, 0x4787C62A );
188 P( C, D, A, B, 6, 17, 0xA8304613 );
189 P( B, C, D, A, 7, 22, 0xFD469501 );
190 P( A, B, C, D, 8, 7, 0x698098D8 );
191 P( D, A, B, C, 9, 12, 0x8B44F7AF );
192 P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
193 P( B, C, D, A, 11, 22, 0x895CD7BE );
194 P( A, B, C, D, 12, 7, 0x6B901122 );
195 P( D, A, B, C, 13, 12, 0xFD987193 );
196 P( C, D, A, B, 14, 17, 0xA679438E );
197 P( B, C, D, A, 15, 22, 0x49B40821 );
198
199#undef F
200
201#define F(x,y,z) (y ^ (z & (x ^ y)))
202
203 P( A, B, C, D, 1, 5, 0xF61E2562 );
204 P( D, A, B, C, 6, 9, 0xC040B340 );
205 P( C, D, A, B, 11, 14, 0x265E5A51 );
206 P( B, C, D, A, 0, 20, 0xE9B6C7AA );
207 P( A, B, C, D, 5, 5, 0xD62F105D );
208 P( D, A, B, C, 10, 9, 0x02441453 );
209 P( C, D, A, B, 15, 14, 0xD8A1E681 );
210 P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
211 P( A, B, C, D, 9, 5, 0x21E1CDE6 );
212 P( D, A, B, C, 14, 9, 0xC33707D6 );
213 P( C, D, A, B, 3, 14, 0xF4D50D87 );
214 P( B, C, D, A, 8, 20, 0x455A14ED );
215 P( A, B, C, D, 13, 5, 0xA9E3E905 );
216 P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
217 P( C, D, A, B, 7, 14, 0x676F02D9 );
218 P( B, C, D, A, 12, 20, 0x8D2A4C8A );
219
220#undef F
221
222#define F(x,y,z) (x ^ y ^ z)
223
224 P( A, B, C, D, 5, 4, 0xFFFA3942 );
225 P( D, A, B, C, 8, 11, 0x8771F681 );
226 P( C, D, A, B, 11, 16, 0x6D9D6122 );
227 P( B, C, D, A, 14, 23, 0xFDE5380C );
228 P( A, B, C, D, 1, 4, 0xA4BEEA44 );
229 P( D, A, B, C, 4, 11, 0x4BDECFA9 );
230 P( C, D, A, B, 7, 16, 0xF6BB4B60 );
231 P( B, C, D, A, 10, 23, 0xBEBFBC70 );
232 P( A, B, C, D, 13, 4, 0x289B7EC6 );
233 P( D, A, B, C, 0, 11, 0xEAA127FA );
234 P( C, D, A, B, 3, 16, 0xD4EF3085 );
235 P( B, C, D, A, 6, 23, 0x04881D05 );
236 P( A, B, C, D, 9, 4, 0xD9D4D039 );
237 P( D, A, B, C, 12, 11, 0xE6DB99E5 );
238 P( C, D, A, B, 15, 16, 0x1FA27CF8 );
239 P( B, C, D, A, 2, 23, 0xC4AC5665 );
240
241#undef F
242
243#define F(x,y,z) (y ^ (x | ~z))
244
245 P( A, B, C, D, 0, 6, 0xF4292244 );
246 P( D, A, B, C, 7, 10, 0x432AFF97 );
247 P( C, D, A, B, 14, 15, 0xAB9423A7 );
248 P( B, C, D, A, 5, 21, 0xFC93A039 );
249 P( A, B, C, D, 12, 6, 0x655B59C3 );
250 P( D, A, B, C, 3, 10, 0x8F0CCC92 );
251 P( C, D, A, B, 10, 15, 0xFFEFF47D );
252 P( B, C, D, A, 1, 21, 0x85845DD1 );
253 P( A, B, C, D, 8, 6, 0x6FA87E4F );
254 P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
255 P( C, D, A, B, 6, 15, 0xA3014314 );
256 P( B, C, D, A, 13, 21, 0x4E0811A1 );
257 P( A, B, C, D, 4, 6, 0xF7537E82 );
258 P( D, A, B, C, 11, 10, 0xBD3AF235 );
259 P( C, D, A, B, 2, 15, 0x2AD7D2BB );
260 P( B, C, D, A, 9, 21, 0xEB86D391 );
261
262#undef F
263
264 ctx->state[0] += A;
265 ctx->state[1] += B;
266 ctx->state[2] += C;
267 ctx->state[3] += D;
268}
269
270/*
271 * MD5 process buffer
272 */
273void md5_update( md5_context *ctx, unsigned char *input, int ilen )
274{
275 int fill;
276 unsigned long left;
277
278 if( ilen <= 0 )
279 return;
280
281 left = ctx->total[0] & 0x3F;
282 fill = 64 - left;
283
284 ctx->total[0] += ilen;
285 ctx->total[0] &= 0xFFFFFFFF;
286
287 if( ctx->total[0] < (unsigned long) ilen )
288 ctx->total[1]++;
289
290 if( left && ilen >= fill )
291 {
292 memcpy( (void *) (ctx->buffer + left),
293 (void *) input, fill );
294 md5_process( ctx, ctx->buffer );
295 input += fill;
296 ilen -= fill;
297 left = 0;
298 }
299
300 while( ilen >= 64 )
301 {
302 md5_process( ctx, input );
303 input += 64;
304 ilen -= 64;
305 }
306
307 if( ilen > 0 )
308 {
309 memcpy( (void *) (ctx->buffer + left),
310 (void *) input, ilen );
311 }
312}
313
314static const unsigned char md5_padding[64] =
315{
316 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
318 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
320};
321
322/*
323 * MD5 final digest
324 */
325void md5_finish( md5_context *ctx, unsigned char output[16] )
326{
327 unsigned long last, padn;
328 unsigned long high, low;
329 unsigned char msglen[8];
330
331 high = ( ctx->total[0] >> 29 )
332 | ( ctx->total[1] << 3 );
333 low = ( ctx->total[0] << 3 );
334
335 PUT_ULONG_LE( low, msglen, 0 );
336 PUT_ULONG_LE( high, msglen, 4 );
337
338 last = ctx->total[0] & 0x3F;
339 padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
340
341 md5_update( ctx, (unsigned char *) md5_padding, padn );
342 md5_update( ctx, msglen, 8 );
343
344 PUT_ULONG_LE( ctx->state[0], output, 0 );
345 PUT_ULONG_LE( ctx->state[1], output, 4 );
346 PUT_ULONG_LE( ctx->state[2], output, 8 );
347 PUT_ULONG_LE( ctx->state[3], output, 12 );
348}
349
350/*
351 * output = MD5( input buffer )
352 */
353void md5( unsigned char *input, int ilen, unsigned char output[16] )
354{
355 md5_context ctx;
356
357 md5_starts( &ctx );
358 md5_update( &ctx, input, ilen );
359 md5_finish( &ctx, output );
360
361 memset( &ctx, 0, sizeof( md5_context ) );
362}
363
364unsigned int md5hash ( const void * input, int len, unsigned int /*seed*/ )
365{
366 unsigned int hash[4];
367
368 md5((unsigned char *)input,len,(unsigned char *)hash);
369
370 //return hash[0] ^ hash[1] ^ hash[2] ^ hash[3];
371
372 return hash[0];
373}
374
375void md5_32 ( const void * key, int len, uint32_t /*seed*/, void * out )
376{
377 unsigned int hash[4];
378
379 md5((unsigned char*)key,len,(unsigned char*)hash);
380
381 *(uint32_t*)out = hash[0];
tanjent@gmail.com7e5c3632010-11-02 00:50:04 +0000382}