2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * This is work is derived from material Copyright RSA Data Security, Inc.
21 * The RSA copyright statement and Licence for that original material is
22 * included below. This is followed by the Apache copyright statement and
23 * licence for the modifications made to that material.
26 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
29 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
32 License to copy and use this software is granted provided that it
33 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
34 Algorithm" in all material mentioning or referencing this software
37 License is also granted to make and use derivative works provided
38 that such works are identified as "derived from the RSA Data
39 Security, Inc. MD5 Message-Digest Algorithm" in all material
40 mentioning or referencing the derived work.
42 RSA Data Security, Inc. makes no representations concerning either
43 the merchantability of this software or the suitability of this
44 software for any particular purpose. It is provided "as is"
45 without express or implied warranty of any kind.
47 These notices must be retained in any copies of any part of this
48 documentation and/or software.
52 * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
53 * MD5 crypt() function, which is licenced as follows:
54 * ----------------------------------------------------------------------------
55 * "THE BEER-WARE LICENSE" (Revision 42):
56 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
57 * can do whatever you want with this stuff. If we meet some day, and you think
58 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
59 * ----------------------------------------------------------------------------
62 /***************************************************************************
63 * Description: MD5 encoding wrapper *
64 * Author: Henri Gomez <hgomez@apache.org> *
65 * Version: $Revision: 466585 $ *
66 ***************************************************************************/
69 * JK MD5 Encoding function (jk_MD5Encode)
71 * Jk delegate MD5 encoding to ap_MD5Encode when used in Apache Web-Server.
72 * When another web-server is used like NES/IIS, we should use corresponding calls.
73 * NES/IIS specialists will add the necessary code but until that, I reused the code
74 * from Apache HTTP server.
76 * Nota: If you use an EBCDIC system without Apache, you'll have to use MD5 encoding
77 * corresponding call or have a ebcdic2ascii() functions somewhere.
78 * For example current AS/400 have MD5 encoding support APIs but olders not....
81 #include "jk_global.h"
84 char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n)
88 static unsigned char zitohex[] = "0123456789ABCDEF";
92 *dst++ = zitohex[v >> 4];
93 *dst++ = zitohex[v & 0x0f];
100 #ifndef USE_APACHE_MD5
102 /* Constants for MD5Transform routine.
122 static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]);
123 static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len);
124 static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len);
125 static void jk_MD5Init(JK_MD5_CTX * context);
126 static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input,
128 /*static void jk_MD5Final(unsigned char digest[JK_MD5_DIGESTSIZE], JK_MD5_CTX *context);*/
130 static unsigned char PADDING[64] = {
131 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
136 /* F, G, H and I are basic MD5 functions.
138 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
139 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
140 #define H(x, y, z) ((x) ^ (y) ^ (z))
141 #define I(x, y, z) ((y) ^ ((x) | (~z)))
143 /* ROTATE_LEFT rotates x left n bits.
145 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
147 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
148 Rotation is separate from addition to prevent recomputation.
150 #define FF(a, b, c, d, x, s, ac) { \
151 (a) += F ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
152 (a) = ROTATE_LEFT ((a), (s)); \
155 #define GG(a, b, c, d, x, s, ac) { \
156 (a) += G ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
157 (a) = ROTATE_LEFT ((a), (s)); \
160 #define HH(a, b, c, d, x, s, ac) { \
161 (a) += H ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
162 (a) = ROTATE_LEFT ((a), (s)); \
165 #define II(a, b, c, d, x, s, ac) { \
166 (a) += I ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
167 (a) = ROTATE_LEFT ((a), (s)); \
171 /* MD5 initialization. Begins an MD5 operation, writing a new context.
173 static void jk_MD5Init(JK_MD5_CTX * context)
175 context->count[0] = context->count[1] = 0;
176 /* Load magic initialization constants. */
177 context->state[0] = 0x67452301;
178 context->state[1] = 0xefcdab89;
179 context->state[2] = 0x98badcfe;
180 context->state[3] = 0x10325476;
183 /* MD5 block update operation. Continues an MD5 message-digest
184 operation, processing another message block, and updating the
187 static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input,
190 size_t i, idx, partLen;
192 /* Compute number of bytes mod 64 */
193 idx = (size_t) ((context->count[0] >> 3) & 0x3F);
195 /* Update number of bits */
196 if ((context->count[0] += ((jk_uint32_t) inputLen << 3))
197 < ((jk_uint32_t) inputLen << 3)) {
200 context->count[1] += (jk_uint32_t) inputLen >> 29;
204 /* Transform as many times as possible. */
205 #ifndef CHARSET_EBCDIC
206 if (inputLen >= partLen) {
207 memcpy(&context->buffer[idx], input, partLen);
208 MD5Transform(context->state, context->buffer);
210 for (i = partLen; i + 63 < inputLen; i += 64) {
211 MD5Transform(context->state, &input[i]);
220 /* Buffer remaining input */
221 memcpy(&context->buffer[idx], &input[i], inputLen - i);
222 #else /*CHARSET_EBCDIC */
223 if (inputLen >= partLen) {
224 ebcdic2ascii(&context->buffer[idx], input, partLen);
225 MD5Transform(context->state, context->buffer);
227 for (i = partLen; i + 63 < inputLen; i += 64) {
228 unsigned char inp_tmp[64];
229 ebcdic2ascii(inp_tmp, &input[i], 64);
230 MD5Transform(context->state, inp_tmp);
239 /* Buffer remaining input */
240 ebcdic2ascii(&context->buffer[idx], &input[i], inputLen - i);
241 #endif /*CHARSET_EBCDIC */
244 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
245 the message digest and zeroizing the context.
247 static void JK_METHOD jk_MD5Final(unsigned char digest[16], JK_MD5_CTX * context)
249 unsigned char bits[8];
253 /* Save number of bits */
254 Encode(bits, context->count, 8);
256 #ifdef CHARSET_EBCDIC
257 /* XXX: @@@: In order to make this no more complex than necessary,
258 * this kludge converts the bits[] array using the ascii-to-ebcdic
259 * table, because the following jk_MD5Update() re-translates
260 * its input (ebcdic-to-ascii).
261 * Otherwise, we would have to pass a "conversion" flag to jk_MD5Update()
263 ascii2ebcdic(bits, bits, 8);
265 /* Since everything is converted to ascii within jk_MD5Update(),
266 * the initial 0x80 (PADDING[0]) must be stored as 0x20
268 ascii2ebcdic(PADDING, PADDING, 1);
269 #endif /*CHARSET_EBCDIC */
271 /* Pad out to 56 mod 64. */
272 idx = (size_t) ((context->count[0] >> 3) & 0x3f);
273 padLen = (idx < 56) ? (56 - idx) : (120 - idx);
274 jk_MD5Update(context, (const unsigned char *)PADDING, padLen);
276 /* Append length (before padding) */
277 jk_MD5Update(context, (const unsigned char *)bits, 8);
279 /* Store state in digest */
280 Encode(digest, context->state, 16);
282 /* Zeroize sensitive information. */
283 memset(context, 0, sizeof(*context));
286 /* MD5 basic transformation. Transforms state based on block. */
287 static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64])
289 jk_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
291 Decode(x, block, 64);
294 FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
295 FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
296 FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
297 FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
298 FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
299 FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
300 FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
301 FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
302 FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
303 FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
304 FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
305 FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
306 FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
307 FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
308 FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
309 FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
312 GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
313 GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
314 GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
315 GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
316 GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
317 GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
318 GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
319 GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
320 GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
321 GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
322 GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
323 GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
324 GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
325 GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
326 GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
327 GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
330 HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
331 HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
332 HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
333 HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
334 HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
335 HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
336 HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
337 HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
338 HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
339 HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
340 HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
341 HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
342 HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
343 HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
344 HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
345 HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
348 II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
349 II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
350 II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
351 II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
352 II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
353 II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
354 II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
355 II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
356 II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
357 II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
358 II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
359 II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
360 II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
361 II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
362 II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
363 II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
370 /* Zeroize sensitive information. */
371 memset(x, 0, sizeof(x));
374 /* Encodes input (jk_uint32_t) into output (unsigned char). Assumes len is
377 static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len)
382 for (i = 0, j = 0; j < len; i++, j += 4) {
384 output[j] = (unsigned char)(k & 0xff);
385 output[j + 1] = (unsigned char)((k >> 8) & 0xff);
386 output[j + 2] = (unsigned char)((k >> 16) & 0xff);
387 output[j + 3] = (unsigned char)((k >> 24) & 0xff);
391 /* Decodes input (unsigned char) into output (jk_uint32_t). Assumes len is
394 static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len)
398 for (i = 0, j = 0; j < len; i++, j += 4)
399 output[i] = ((jk_uint32_t) input[j]) | (((jk_uint32_t) input[j + 1]) << 8) |
400 (((jk_uint32_t) input[j + 2]) << 16) | (((jk_uint32_t) input[j + 3]) <<
404 char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2,
408 char buf[JK_MD5_DIGESTSIZE + 1];
411 jk_MD5Update(&ctx, org, strlen((const char *)org));
414 jk_MD5Update(&ctx, org2, strlen((const char *)org2));
416 jk_MD5Final((unsigned char *)buf, &ctx);
417 return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE));
420 #else /* USE_APACHE_MD5 */
423 #include "http_config.h"
425 #ifdef STANDARD20_MODULE_STUFF
428 #define AP_MD5_CTX apr_md5_ctx_t
429 #define ap_MD5Init apr_md5_init
430 #define ap_MD5Update apr_md5_update
431 #define ap_MD5Final apr_md5_final
433 #else /* STANDARD20_MODULE_STUFF */
437 #endif /* STANDARD20_MODULE_STUFF */
439 char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2,
443 char buf[JK_MD5_DIGESTSIZE + 1];
446 ap_MD5Update(&ctx, org, strlen((const char *)org));
449 ap_MD5Update(&ctx, org2, strlen((const char *)org2));
451 ap_MD5Final((unsigned char *)buf, &ctx);
452 return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE));
455 #endif /* USE_APACHE_MD5 */
458 * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E
459 * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61
460 * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72
461 * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0
467 main(int argc, char **argv)
469 char xxx[(2 * JK_MD5_DIGESTSIZE) + 1];
472 printf("%s => %s\n", argv[1], jk_md5(argv[1], NULL, xxx));