Avail feature updated
[ninja.git] / cli-helpers / apr_md5_validate.c
blob940404a4d7a79693a2b7694181e0fd364723f549
1 /*
2 * This is work is derived from material Copyright RSA Data Security, Inc.
4 * The RSA copyright statement and Licence for that original material is
5 * included below. This is followed by the Apache copyright statement and
6 * licence for the modifications made to that material.
7 */
9 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
10 rights reserved.
12 License to copy and use this software is granted provided that it
13 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
14 Algorithm" in all material mentioning or referencing this software
15 or this function.
17 License is also granted to make and use derivative works provided
18 that such works are identified as "derived from the RSA Data
19 Security, Inc. MD5 Message-Digest Algorithm" in all material
20 mentioning or referencing the derived work.
22 RSA Data Security, Inc. makes no representations concerning either
23 the merchantability of this software or the suitability of this
24 software for any particular purpose. It is provided "as is"
25 without express or implied warranty of any kind.
27 These notices must be retained in any copies of any part of this
28 documentation and/or software.
31 /* Licensed to the Apache Software Foundation (ASF) under one or more
32 * contributor license agreements. See the NOTICE file distributed with
33 * this work for additional information regarding copyright ownership.
34 * The ASF licenses this file to You under the Apache License, Version 2.0
35 * (the "License"); you may not use this file except in compliance with
36 * the License. You may obtain a copy of the License at
38 * http://www.apache.org/licenses/LICENSE-2.0
40 * Unless required by applicable law or agreed to in writing, software
41 * distributed under the License is distributed on an "AS IS" BASIS,
42 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
43 * See the License for the specific language governing permissions and
44 * limitations under the License.
48 * Nearly all code in this file was taken from the apr library as found
49 * in the Apache Software Foundation's subversion repository for the 'apr'
50 * utility library. The code has been restructured to isolate the
51 * apr_md5_encode() function, which creates salted md5 hashes of
52 * text-strings. The hashes thus created are suitable to use for
53 * password storage.
55 * The idea is that php applications that previously relied on basic-auth
56 * can convert to using its own authentication scheme without forcing
57 * users to re-create their passwords.
59 * Do note that this application is not very secure, as it takes both
60 * the plaintext and the hashed password as command-line arguments. It
61 * can most certainly be improved, but it suffices for our simple needs
63 * It's safe to assume that any and all bugs in the code was introduced
64 * by me.
66 * /Andreas Ericsson <ae@op5.com>
69 #include <sys/types.h>
70 #include <limits.h>
71 #include <stdint.h>
73 #include <stdio.h>
74 #include <string.h>
75 #include <crypt.h>
76 #include <unistd.h>
78 /* The MD5 digest size */
79 #define APR_MD5_DIGESTSIZE 16
81 /* MD5 context. */
82 struct apr_md5_ctx_t {
83 uint32_t state[4]; /* state (ABCD) */
84 uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
85 unsigned char buffer[64]; /* input buffer */
88 typedef struct apr_md5_ctx_t apr_md5_ctx_t;
90 /* Constants for MD5Transform routine. */
91 #define S11 7
92 #define S12 12
93 #define S13 17
94 #define S14 22
95 #define S21 5
96 #define S22 9
97 #define S23 14
98 #define S24 20
99 #define S31 4
100 #define S32 11
101 #define S33 16
102 #define S34 23
103 #define S41 6
104 #define S42 10
105 #define S43 15
106 #define S44 21
108 static const unsigned char PADDING[64] =
110 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
115 #define DO_XLATE 0
116 #define SKIP_XLATE 1
118 /* F, G, H and I are basic MD5 functions. */
119 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
120 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
121 #define H(x, y, z) ((x) ^ (y) ^ (z))
122 #define I(x, y, z) ((y) ^ ((x) | (~z)))
124 /* ROTATE_LEFT rotates x left n bits. */
125 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
127 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
128 * Rotation is separate from addition to prevent recomputation.
130 #define FF(a, b, c, d, x, s, ac) { \
131 (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
132 (a) = ROTATE_LEFT ((a), (s)); \
133 (a) += (b); \
135 #define GG(a, b, c, d, x, s, ac) { \
136 (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
137 (a) = ROTATE_LEFT ((a), (s)); \
138 (a) += (b); \
140 #define HH(a, b, c, d, x, s, ac) { \
141 (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
142 (a) = ROTATE_LEFT ((a), (s)); \
143 (a) += (b); \
145 #define II(a, b, c, d, x, s, ac) { \
146 (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
147 (a) = ROTATE_LEFT ((a), (s)); \
148 (a) += (b); \
152 /* Encodes input (uint32_t) into output (unsigned char). Assumes len is
153 * a multiple of 4. */
154 static void Encode(unsigned char *output, const uint32_t *input,
155 unsigned int len)
157 unsigned int i, j;
158 uint32_t k;
160 for (i = 0, j = 0; j < len; i++, j += 4) {
161 k = input[i];
162 output[j] = (unsigned char)(k & 0xff);
163 output[j + 1] = (unsigned char)((k >> 8) & 0xff);
164 output[j + 2] = (unsigned char)((k >> 16) & 0xff);
165 output[j + 3] = (unsigned char)((k >> 24) & 0xff);
169 /* Decodes input (unsigned char) into output (uint32_t). Assumes len is
170 * a multiple of 4. */
171 static void Decode(uint32_t *output, const unsigned char *input,
172 unsigned int len)
174 unsigned int i, j;
176 for (i = 0, j = 0; j < len; i++, j += 4)
177 output[i] = ((uint32_t)input[j]) |
178 (((uint32_t)input[j + 1]) << 8) |
179 (((uint32_t)input[j + 2]) << 16) |
180 (((uint32_t)input[j + 3]) << 24);
184 /* MD5 basic transformation. Transforms state based on block. */
185 static void MD5Transform(uint32_t state[4], const unsigned char block[64])
187 uint32_t a = state[0], b = state[1], c = state[2], d = state[3],
188 x[APR_MD5_DIGESTSIZE];
190 Decode(x, block, 64);
192 /* Round 1 */
193 FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
194 FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
195 FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
196 FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
197 FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
198 FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
199 FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
200 FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
201 FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
202 FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
203 FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
204 FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
205 FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
206 FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
207 FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
208 FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
210 /* Round 2 */
211 GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
212 GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
213 GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
214 GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
215 GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
216 GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
217 GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
218 GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
219 GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
220 GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
221 GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
222 GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
223 GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
224 GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
225 GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
226 GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
228 /* Round 3 */
229 HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
230 HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
231 HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
232 HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
233 HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
234 HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
235 HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
236 HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
237 HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
238 HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
239 HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
240 HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
241 HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
242 HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
243 HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
244 HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
246 /* Round 4 */
247 II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
248 II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
249 II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
250 II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
251 II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
252 II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
253 II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
254 II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
255 II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
256 II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
257 II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
258 II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
259 II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
260 II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
261 II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
262 II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
264 state[0] += a;
265 state[1] += b;
266 state[2] += c;
267 state[3] += d;
269 /* Zeroize sensitive information. */
270 memset(x, 0, sizeof(x));
273 /* MD5 initialization. Begins an MD5 operation, writing a new context.
275 static int apr_md5_init(apr_md5_ctx_t *context)
277 context->count[0] = context->count[1] = 0;
279 /* Load magic initialization constants. */
280 context->state[0] = 0x67452301;
281 context->state[1] = 0xefcdab89;
282 context->state[2] = 0x98badcfe;
283 context->state[3] = 0x10325476;
285 return 0;
288 /* MD5 block update operation. Continues an MD5 message-digest
289 * operation, processing another message block, and updating the
290 * context. */
291 static int md5_update_buffer(apr_md5_ctx_t *context,
292 const void *vinput,
293 size_t inputLen,
294 int xlate_buffer)
296 const unsigned char *input = vinput;
297 unsigned int i, idx, partLen;
299 /* Compute number of bytes mod 64 */
300 idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
302 /* Update number of bits */
303 if ((context->count[0] += ((uint32_t)inputLen << 3))
304 < ((uint32_t)inputLen << 3))
305 context->count[1]++;
306 context->count[1] += (uint32_t)inputLen >> 29;
308 partLen = 64 - idx;
310 /* Transform as many times as possible. */
311 if (inputLen >= partLen) {
312 memcpy(&context->buffer[idx], input, partLen);
313 MD5Transform(context->state, context->buffer);
315 for (i = partLen; i + 63 < inputLen; i += 64)
316 MD5Transform(context->state, &input[i]);
318 idx = 0;
320 else
321 i = 0;
323 /* Buffer remaining input */
324 memcpy(&context->buffer[idx], &input[i], inputLen - i);
325 return 0;
328 /* MD5 block update operation. API with the default setting
329 * for EBCDIC translations */
330 static int apr_md5_update(apr_md5_ctx_t *context, const void *input, size_t inputLen)
332 return md5_update_buffer(context, input, inputLen, DO_XLATE);
335 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
336 * the message digest and zeroizing the context */
337 static int apr_md5_final(unsigned char digest[APR_MD5_DIGESTSIZE],
338 apr_md5_ctx_t *context)
340 unsigned char bits[8];
341 unsigned int idx, padLen;
343 /* Save number of bits */
344 Encode(bits, context->count, 8);
346 /* Pad out to 56 mod 64. */
347 idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
348 padLen = (idx < 56) ? (56 - idx) : (120 - idx);
349 apr_md5_update(context, PADDING, padLen);
351 /* Append length (before padding) */
352 apr_md5_update(context, bits, 8);
354 /* Store state in digest */
355 Encode(digest, context->state, APR_MD5_DIGESTSIZE);
357 /* Zeroize sensitive information. */
358 memset(context, 0, sizeof(*context));
360 return 0;
364 * Define the Magic String prefix that identifies a password as being
365 * hashed using our algorithm.
367 static const char *apr1_id = "$apr1$";
370 * The following MD5 password encryption code was largely borrowed from
371 * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
372 * licenced as stated at the top of this file.
375 static void to64(char *s, unsigned long v, int n)
377 static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
378 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
380 while (--n >= 0) {
381 *s++ = itoa64[v&0x3f];
382 v >>= 6;
386 static int apr_md5_encode(const char *pw, const char *salt,
387 char *result, size_t nbytes)
390 * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
391 * plus 4 for the '$' separators, plus the password hash itself.
392 * Let's leave a goodly amount of leeway.
395 char passwd[120], *p;
396 const char *sp, *ep;
397 unsigned char final[APR_MD5_DIGESTSIZE];
398 ssize_t sl, pl, i;
399 apr_md5_ctx_t ctx, ctx1;
400 unsigned long l;
403 * Refine the salt first. It's possible we were given an already-hashed
404 * string as the salt argument, so extract the actual salt value from it
405 * if so. Otherwise just use the string up to the first '$' as the salt.
407 sp = salt;
410 * If it starts with the magic string, then skip that.
412 if (!strncmp(sp, apr1_id, strlen(apr1_id))) {
413 sp += strlen(apr1_id);
417 * It stops at the first '$' or 8 chars, whichever comes first
419 for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
420 continue;
424 * Get the length of the true salt
426 sl = ep - sp;
429 * 'Time to make the doughnuts..'
431 apr_md5_init(&ctx);
434 * The password first, since that is what is most unknown
436 apr_md5_update(&ctx, pw, strlen(pw));
439 * Then our magic string
441 apr_md5_update(&ctx, apr1_id, strlen(apr1_id));
444 * Then the raw salt
446 apr_md5_update(&ctx, sp, sl);
449 * Then just as many characters of the MD5(pw, salt, pw)
451 apr_md5_init(&ctx1);
452 apr_md5_update(&ctx1, pw, strlen(pw));
453 apr_md5_update(&ctx1, sp, sl);
454 apr_md5_update(&ctx1, pw, strlen(pw));
455 apr_md5_final(final, &ctx1);
456 for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
457 md5_update_buffer(&ctx, final,
458 (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl, SKIP_XLATE);
462 * Don't leave anything around in vm they could use.
464 memset(final, 0, sizeof(final));
467 * Then something really weird...
469 for (i = strlen(pw); i != 0; i >>= 1) {
470 if (i & 1) {
471 md5_update_buffer(&ctx, final, 1, SKIP_XLATE);
473 else {
474 apr_md5_update(&ctx, pw, 1);
479 * Now make the output string. We know our limitations, so we
480 * can use the string routines without bounds checking.
482 strcpy(passwd, apr1_id);
483 strncat(passwd, sp, sl);
484 strcat(passwd, "$");
486 apr_md5_final(final, &ctx);
489 * And now, just to make sure things don't run too fast..
490 * On a 60 Mhz Pentium this takes 34 msec, so you would
491 * need 30 seconds to build a 1000 entry dictionary...
493 for (i = 0; i < 1000; i++) {
494 apr_md5_init(&ctx1);
496 * apr_md5_final clears out ctx1.xlate at the end of each loop,
497 * so need to to set it each time through
499 if (i & 1) {
500 apr_md5_update(&ctx1, pw, strlen(pw));
502 else {
503 md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE);
505 if (i % 3) {
506 apr_md5_update(&ctx1, sp, sl);
509 if (i % 7) {
510 apr_md5_update(&ctx1, pw, strlen(pw));
513 if (i & 1) {
514 md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE);
516 else {
517 apr_md5_update(&ctx1, pw, strlen(pw));
519 apr_md5_final(final,&ctx1);
522 p = passwd + strlen(passwd);
524 l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
525 l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
526 l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
527 l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
528 l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
529 l = final[11] ; to64(p, l, 2); p += 2;
530 *p = '\0';
533 * Don't leave anything around in vm they could use.
535 memset(final, 0, sizeof(final));
537 strncpy(result, passwd, nbytes - 1);
538 return 0;
541 #define prefixcmp(a, b) strncmp(a, b, strlen(b))
542 int main(int argc, char **argv)
544 char sample[120];
545 char *plain, *hash;
547 if (argc != 3) {
548 printf("Usage: %s <plaintext password> <hashed password>\n", argv[0]);
549 return 1;
552 plain = argv[1];
553 hash = argv[2];
555 if (prefixcmp(hash, apr1_id)) {
556 printf("Password is not encrypted using apache's md5 hash algorithm\n");
557 return 1;
560 if (apr_md5_encode(plain, hash, sample, sizeof(sample)) < 0) {
561 printf("md5 encoding failed");
562 return 1;
565 if (!strcmp(hash, sample)) {
566 printf("password matches\n");
567 return 0;
570 printf("password mismatch\n");
571 return 1;