1    | /*
2    |  * ----------------------------------------------------------------------------
3    |  * "THE BEER-WARE LICENSE" (Revision 42):
4    |  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5    |  * can do whatever you want with this stuff. If we meet some day, and you think
6    |  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7    |  * ----------------------------------------------------------------------------
8    |  */
9    | 
10   | /* #include <sys/cdefs.h>
11   | __FBSDID("$FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.12 2002/03/25 15:55:36 phk Exp $");
12   | */
13   | #include <config.h>
14   | #include <unistd.h>
15   | #include <stdio.h>
16   | #include <string.h>
17   | #include <md5.h>
18   | /* #include <err.h> */
19   | #include "crypt.h"
20   | 
21   | /*
22   |  * UNIX password
23   |  */
24   | 
25   | char *
26   | crypt_md5(const char *pw, const char *salt)
27   | {
28   |         MD5_CTX ctx,ctx1;
29   |         unsigned long l;
30   |         int sl, pl;
31   |         u_int i;
32   |         u_char final[MD5_SIZE];
33   |         static const char *sp, *ep;
34   |         static char passwd[120], *p;
35   |         static const char *magic = "$1$";       /*
36   |                                                  * This string is magic for
37   |                                                  * this algorithm.  Having
38   |                                                  * it this way, we can get
39   |                                                  * better later on.
40   |                                                  */
41   | 
42   |         /* Refine the Salt first */
43   |         sp = salt;
44   | 
45   |         /* If it starts with the magic string, then skip that */
46   |         if(!strncmp(sp, magic, strlen(magic)))
47   |                 sp += strlen(magic);
48   | 
49   |         /* It stops at the first '$', max 8 chars */
50   |         for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
51   |                 continue;
52   | 
53   |         /* get the length of the true salt */
54   |         sl = ep - sp;
55   | 
56   |         MD5Init(&ctx);
57   | 
58   |         /* The password first, since that is what is most unknown */
59   |         MD5Update(&ctx, (u_char *)pw, strlen(pw));
60   | 
61   |         /* Then our magic string */
62   |         MD5Update(&ctx, (u_char *)magic, strlen(magic));
63   | 
64   |         /* Then the raw salt */
65   |         MD5Update(&ctx, (u_char *)sp, (u_int)sl);
66   | 
67   |         /* Then just as many characters of the MD5(pw,salt,pw) */
68   |         MD5Init(&ctx1);
69   |         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
70   |         MD5Update(&ctx1, (u_char *)sp, (u_int)sl);
71   |         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
72   |         MD5Final(final, &ctx1);
73   |         for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
74   |                 MD5Update(&ctx, (u_char *)final,
75   |                     (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
76   | 
77   |         /* Don't leave anything around in vm they could use. */
78   |         memset(final, 0, sizeof(final));
79   | 
80   |         /* Then something really weird... */
81   |         for (i = strlen(pw); i; i >>= 1)
82   |                 if(i & 1)
83   |                     MD5Update(&ctx, (u_char *)final, 1);
84   |                 else
85   |                     MD5Update(&ctx, (u_char *)pw, 1);
86   | 
87   |         /* Now make the output string */
88   |         strcpy(passwd, magic);
89   |         strncat(passwd, sp, (u_int)sl);
90   |         strcat(passwd, "$");
91   | 
92   |         MD5Final(final, &ctx);
93   | 
94   |         /*
95   |          * and now, just to make sure things don't run too fast
96   |          * On a 60 Mhz Pentium this takes 34 msec, so you would
97   |          * need 30 seconds to build a 1000 entry dictionary...
98   |          */
99   |         for(i = 0; i < 1000; i++) {
100  |                 MD5Init(&ctx1);
101  |                 if(i & 1)
102  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
103  |                 else
104  |                         MD5Update(&ctx1, (u_char *)final, MD5_SIZE);
105  | 
106  |                 if(i % 3)
107  |                         MD5Update(&ctx1, (u_char *)sp, (u_int)sl);
108  | 
109  |                 if(i % 7)
110  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
111  | 
112  |                 if(i & 1)
113  |                         MD5Update(&ctx1, (u_char *)final, MD5_SIZE);
114  |                 else
115  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
116  |                 MD5Final(final, &ctx1);
117  |         }
118  | 
119  |         p = passwd + strlen(passwd);
120  | 
121  |         l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
122  |         _crypt_to64(p, l, 4); p += 4;
123  |         l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
124  |         _crypt_to64(p, l, 4); p += 4;
125  |         l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
126  |         _crypt_to64(p, l, 4); p += 4;
127  |         l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
128  |         _crypt_to64(p, l, 4); p += 4;
129  |         l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
130  |         _crypt_to64(p, l, 4); p += 4;
131  |         l =                    final[11]                ;
132  |         _crypt_to64(p, l, 2); p += 2;
133  |         *p = '\0';
134  | 
135  |         /* Don't leave anything around in vm they could use. */
136  |         memset(final, 0, sizeof(final));
137  | 
138  |         return passwd;
139  | }
140  | 
141  |