Add support for Unix-standard MD5 password
[profile/ivi/syslinux.git] / com32 / libutil / crypt-md5.c
1 /*-
2  * Copyright (c) 2003 Poul-Henning Kamp
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <inttypes.h>
28 #include <md5.h>
29 #include <string.h>
30
31 /*
32  * UNIX password
33  */
34
35 #include "crypt.h"
36
37 static char itoa64[] =          /* 0 ... 63 => ascii - 64 */
38         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
39
40 static void
41 _crypt_to64(char *s, uint32_t v, int n)
42 {
43         while (--n >= 0) {
44                 *s++ = itoa64[v&0x3f];
45                 v >>= 6;
46         }
47 }
48
49 char *
50 crypt_md5(const char *pw, const char *salt)
51 {
52         MD5_CTX ctx,ctx1;
53         unsigned long l;
54         int sl, pl;
55         uint32_t i;
56         uint8_t final[MD5_SIZE];
57         static const char *sp, *ep;
58         static char passwd[120], *p;
59         static const char *magic = "$1$";
60
61         /* Refine the Salt first */
62         sp = salt;
63
64         /* If it starts with the magic string, then skip that */
65         if(!strncmp(sp, magic, strlen(magic)))
66                 sp += strlen(magic);
67
68         /* It stops at the first '$', max 8 chars */
69         for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
70                 continue;
71
72         /* get the length of the true salt */
73         sl = ep - sp;
74
75         MD5Init(&ctx);
76
77         /* The password first, since that is what is most unknown */
78         MD5Update(&ctx, (const uint8_t *)pw, strlen(pw));
79
80         /* Then our magic string */
81         MD5Update(&ctx, (const uint8_t *)magic, strlen(magic));
82
83         /* Then the raw salt */
84         MD5Update(&ctx, (const uint8_t *)sp, (uint32_t)sl);
85
86         /* Then just as many characters of the MD5(pw,salt,pw) */
87         MD5Init(&ctx1);
88         MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw));
89         MD5Update(&ctx1, (const uint8_t *)sp, (uint32_t)sl);
90         MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw));
91         MD5Final(final, &ctx1);
92         for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
93                 MD5Update(&ctx, (const uint8_t *)final,
94                     (uint32_t)(pl > MD5_SIZE ? MD5_SIZE : pl));
95
96         /* Don't leave anything around in vm they could use. */
97         memset(final, 0, sizeof(final));
98
99         /* Then something really weird... */
100         for (i = strlen(pw); i; i >>= 1)
101                 if(i & 1)
102                     MD5Update(&ctx, (const uint8_t *)final, 1);
103                 else
104                     MD5Update(&ctx, (const uint8_t *)pw, 1);
105
106         /* Now make the output string */
107         strcpy(passwd, magic);
108         strncat(passwd, sp, (uint32_t)sl);
109         strcat(passwd, "$");
110
111         MD5Final(final, &ctx);
112
113         /*
114          * and now, just to make sure things don't run too fast
115          * On a 60 Mhz Pentium this takes 34 msec, so you would
116          * need 30 seconds to build a 1000 entry dictionary...
117          */
118         for(i = 0; i < 1000; i++) {
119                 MD5Init(&ctx1);
120                 if(i & 1)
121                         MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw));
122                 else
123                         MD5Update(&ctx1, (const uint8_t *)final, MD5_SIZE);
124
125                 if(i % 3)
126                         MD5Update(&ctx1, (const uint8_t *)sp, (uint32_t)sl);
127
128                 if(i % 7)
129                         MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw));
130
131                 if(i & 1)
132                         MD5Update(&ctx1, (const uint8_t *)final, MD5_SIZE);
133                 else
134                         MD5Update(&ctx1, (const uint8_t *)pw, strlen(pw));
135                 MD5Final(final, &ctx1);
136         }
137
138         p = passwd + strlen(passwd);
139
140         l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
141         _crypt_to64(p, l, 4); p += 4;
142         l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
143         _crypt_to64(p, l, 4); p += 4;
144         l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
145         _crypt_to64(p, l, 4); p += 4;
146         l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
147         _crypt_to64(p, l, 4); p += 4;
148         l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
149         _crypt_to64(p, l, 4); p += 4;
150         l = final[11];
151         _crypt_to64(p, l, 2); p += 2;
152         *p = '\0';
153
154         /* Don't leave anything around in vm they could use. */
155         memset(final, 0, sizeof(final));
156
157         return (passwd);
158 }
159
160 #ifdef TEST
161 #include <stdio.h>
162
163 int main(int argc, char *argv[])
164 {
165   puts(crypt_md5(argv[1], argv[2]));
166   return 0;
167 }
168
169 #endif