blob: b02cbecfa003f2babd9b4c01a654f2a4a5131027 [file] [log] [blame]
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +00001/*
2 * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
3 *
4 * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
5 * rights reserved.
6 *
7 * License to copy and use this software is granted provided that it
8 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
9 * Algorithm" in all material mentioning or referencing this software
10 * or this function.
11 *
12 * License is also granted to make and use derivative works provided
13 * that such works are identified as "derived from the RSA Data
14 * Security, Inc. MD5 Message-Digest Algorithm" in all material
15 * mentioning or referencing the derived work.
16 *
17 * RSA Data Security, Inc. makes no representations concerning either
18 * the merchantability of this software or the suitability of this
19 * software for any particular purpose. It is provided "as is"
20 * without express or implied warranty of any kind.
21 *
22 * These notices must be retained in any copies of any part of this
23 * documentation and/or software.
24 *
25 * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
26 *
27 * This code is the same as the code published by RSA Inc. It has been
28 * edited for clarity and style only.
29 *
30 * ----------------------------------------------------------------------------
31 * The md5_crypt() function was taken from freeBSD's libcrypt and contains
32 * this license:
33 * "THE BEER-WARE LICENSE" (Revision 42):
34 * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
35 * can do whatever you want with this stuff. If we meet some day, and you think
36 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
37 *
38 * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
39 *
40 * ----------------------------------------------------------------------------
41 * On April 19th, 2001 md5_crypt() was modified to make it reentrant
42 * by Erik Andersen <andersen@uclibc.org>
43 *
44 *
45 * June 28, 2001 Manuel Novoa III
46 *
47 * "Un-inlined" code using loops and static const tables in order to
48 * reduce generated code size (on i386 from approx 4k to approx 2.5k).
49 *
50 * June 29, 2001 Manuel Novoa III
51 *
52 * Completely removed static PADDING array.
53 *
54 * Reintroduced the loop unrolling in MD5_Transform and added the
55 * MD5_SIZE_OVER_SPEED option for configurability. Define below as:
56 * 0 fully unrolled loops
57 * 1 partially unrolled (4 ops per loop)
58 * 2 no unrolling -- introduces the need to swap 4 variables (slow)
59 * 3 no unrolling and all 4 loops merged into one with switch
60 * in each loop (glacial)
61 * On i386, sizes are roughly (-Os -fno-builtin):
62 * 0: 3k 1: 2.5k 2: 2.2k 3: 2k
63 *
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000064 * Since SuSv3 does not require crypt_r, modified again August 7, 2002
65 * by Erik Andersen to remove reentrance stuff...
66 */
67
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000068#define MD5_MAGIC_STR "$1$"
69#define MD5_MAGIC_LEN (sizeof(MD5_MAGIC_STR) - 1)
70static const unsigned char __md5__magic[] = MD5_MAGIC_STR;
71
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000072/*
73 * UNIX password
74 *
75 * Use MD5 for what it is best at...
76 */
Denis Vlasenko76f81282008-06-13 15:13:41 +000077#define MD5_OUT_BUFSIZE 36
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000078static char *
Denis Vlasenkoe2352852008-06-14 22:11:29 +000079NOINLINE
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000080md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000081{
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000082 char *p;
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000083 unsigned char final[17]; /* final[16] exists only to aid in looping */
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000084 int sl, pl, i, pw_len;
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000085 md5_ctx_t ctx, ctx1;
86
87 /* NB: in busybox, "$1$" in salt is always present */
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000088
89 /* Refine the Salt first */
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000090
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000091 /* Get the length of the salt including "$1$" */
92 sl = 3;
93 while (salt[sl] && salt[sl] != '$' && sl < (3 + 8))
94 sl++;
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000095
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000096 /* Hash. the password first, since that is what is most unknown */
97 md5_begin(&ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +000098 pw_len = strlen((char*)pw);
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +000099 md5_hash(pw, pw_len, &ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000100
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000101 /* Then the salt including "$1$" */
102 md5_hash(salt, sl, &ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000103
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000104 /* Copy salt to result; skip "$1$" */
105 memcpy(result, salt, sl);
106 result[sl] = '$';
107 salt += 3;
108 sl -= 3;
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000109
110 /* Then just as many characters of the MD5(pw, salt, pw) */
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000111 md5_begin(&ctx1);
112 md5_hash(pw, pw_len, &ctx1);
113 md5_hash(salt, sl, &ctx1);
114 md5_hash(pw, pw_len, &ctx1);
115 md5_end(final, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000116 for (pl = pw_len; pl > 0; pl -= 16)
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000117 md5_hash(final, pl > 16 ? 16 : pl, &ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000118
119 /* Then something really weird... */
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000120 memset(final, 0, sizeof(final));
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000121 for (i = pw_len; i; i >>= 1) {
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000122 md5_hash(((i & 1) ? final : (const unsigned char *) pw), 1, &ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000123 }
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000124 md5_end(final, &ctx);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000125
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000126 /* And now, just to make sure things don't run too fast.
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000127 * On a 60 Mhz Pentium this takes 34 msec, so you would
128 * need 30 seconds to build a 1000 entry dictionary...
129 */
130 for (i = 0; i < 1000; i++) {
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000131 md5_begin(&ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000132 if (i & 1)
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000133 md5_hash(pw, pw_len, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000134 else
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000135 md5_hash(final, 16, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000136
137 if (i % 3)
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000138 md5_hash(salt, sl, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000139
140 if (i % 7)
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000141 md5_hash(pw, pw_len, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000142
143 if (i & 1)
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000144 md5_hash(final, 16, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000145 else
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000146 md5_hash(pw, pw_len, &ctx1);
147 md5_end(final, &ctx1);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000148 }
149
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000150 p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000151
Denis Vlasenko76f81282008-06-13 15:13:41 +0000152 /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000153 final[16] = final[5];
154 for (i = 0; i < 5; i++) {
Denis Vlasenkoe2352852008-06-14 22:11:29 +0000155 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
Denis Vlasenko2211d522008-11-10 18:52:35 +0000156 p = to64(p, l, 4);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000157 }
Denis Vlasenko2211d522008-11-10 18:52:35 +0000158 p = to64(p, final[11], 2);
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000159 *p = '\0';
160
161 /* Don't leave anything around in vm they could use. */
162 memset(final, 0, sizeof(final));
163
Denis Vlasenkoe9b9a192008-11-11 01:38:04 +0000164 return result;
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000165}
Denis Vlasenko4ea83bf2008-06-12 16:55:59 +0000166#undef MD5_MAGIC_STR
167#undef MD5_MAGIC_LEN