1 /*
2  * From crypt implementation 1.7 by Poul-Henning Kamp
3  * ----------------------------------------------------------------------------
4  * "THE BEER-WARE LICENSE" (Revision 42):
5  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
6  * can do whatever you want with this stuff. If we meet some day, and you think
7  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
8  * ----------------------------------------------------------------------------
9  *
10  * Sub-licensed with modifications under AGPL:
11  *
12  * This program is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Affero General Public License version 3.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * In addition, as a special exception, the copyright holders give
24  * permission to link the code of portions of this program with the
25  * OpenSSL library under certain conditions as described in each
26  * individual source file, and distribute linked combinations
27  * including the two.
28  *
29  * You must obey the GNU Affero General Public License in all respects
30  * for all of the code used other than OpenSSL.
31  */
32 
33 #include "config.h"
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 
39 #ifdef HAVE_STDIO_H
40 #include <stdio.h>
41 #endif
42 
43 #ifdef HAVE_STRING_H
44 #include <string.h>
45 #endif
46 
47 #include "md5.h"
48 #include "md5_crypt.h"
49 
50 
51 /* 0 ... 63 => ascii - 64 */
52 static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53 
to64(char * s,unsigned long v,int n)54 static void to64(char *s, unsigned long v, int n) {
55         while (--n >= 0) {
56                 *s++ = itoa64[v & 0x3f];
57                 v >>= 6;
58         }
59 }
60 
61 
62 /*
63  * UNIX password MD5
64  */
md5_crypt(const char * pw,const char * id,const char * salt,char * buf,int buflen)65 char *md5_crypt(const char *pw, const char *id, const char *salt, char *buf, int buflen) {
66         char *p;
67         const md5_byte_t *sp, *ep;
68         unsigned char final[16];
69         int sl, pl, pwl = (int)strlen(pw);
70         unsigned long l;
71         md5_context_t ctx, ctx1;
72 
73         /* Refine the Salt first */
74         sp = (const md5_byte_t *)salt;
75 
76         /* If it starts with the id string, then skip that */
77         if (! strncmp(salt, id, strlen(id)))
78                 sp += strlen(id);
79 
80         /* It stops at the first '$', max 8 chars */
81         for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
82                 continue;
83 
84         /* get the length of the true salt */
85         sl = (int)(ep - sp);
86 
87         md5_init(&ctx);
88 
89         /* The password first, since that is what is most unknown */
90         md5_append(&ctx, (const md5_byte_t *)pw, pwl);
91 
92         /* Then our id string */
93         md5_append(&ctx, (const md5_byte_t *)id, (int)strlen(id));
94 
95         /* Then the raw salt */
96         md5_append(&ctx, sp, sl);
97 
98         /* Then just as many characters of the MD5(pw, salt, pw) */
99         md5_init(&ctx1);
100         md5_append(&ctx1, (const md5_byte_t *)pw, pwl);
101         md5_append(&ctx1, sp, sl);
102         md5_append(&ctx1, (const md5_byte_t *)pw, pwl);
103         md5_finish(&ctx1, final);
104         for (pl = pwl; pl > 0; pl -= 16)
105                 md5_append(&ctx, final, pl > 16 ? 16 : pl);
106 
107         /* Don't leave anything around in vm they could use. */
108         memset(final, 0, sizeof(final));
109 
110         /* Then something really weird... */
111         for (int i = pwl; i; i >>= 1) {
112                 if (i & 1)
113                         md5_append(&ctx, final, 1);
114                 else
115                         md5_append(&ctx, (const md5_byte_t *)pw, 1);
116         }
117 
118         /* Now make the output string */
119         strncpy(buf, id, buflen);
120         strncat(buf, (const char *)sp, sl);
121         strcat(buf, "$");
122 
123         md5_finish(&ctx, final);
124 
125         /*
126          * and now, just to make sure things don't run too fast
127          * 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 (int i = 0; i < 1000; i++) {
131                 md5_init(&ctx1);
132                 if (i & 1)
133                         md5_append(&ctx1, (const md5_byte_t *)pw, pwl);
134                 else
135                         md5_append(&ctx1, final, 16);
136 
137                 if (i % 3)
138                         md5_append(&ctx1, sp, sl);
139 
140                 if (i % 7)
141                         md5_append(&ctx1, (const md5_byte_t *)pw, pwl);
142 
143                 if (i & 1)
144                         md5_append(&ctx1, final, 16);
145                 else
146                         md5_append(&ctx1, (const md5_byte_t *)pw, pwl);
147                 md5_finish(&ctx1, final);
148         }
149 
150         p = buf + strlen(buf);
151 
152         l = (final[ 0] << 16) | (final[ 6] << 8) | final[12]; to64(p, l, 4); p += 4;
153         l = (final[ 1] << 16) | (final[ 7] << 8) | final[13]; to64(p, l, 4); p += 4;
154         l = (final[ 2] << 16) | (final[ 8] << 8) | final[14]; to64(p, l, 4); p += 4;
155         l = (final[ 3] << 16) | (final[ 9] << 8) | final[15]; to64(p, l, 4); p += 4;
156         l = (final[ 4] << 16) | (final[10] << 8) | final[ 5]; to64(p, l, 4); p += 4;
157         l =                        final[11]                ; to64(p, l, 2); p += 2;
158         *p = '\0';
159 
160         /* Don't leave anything around in vm they could use. */
161         memset(final, 0, sizeof(final));
162 
163         return buf;
164 }
165 
166