1 | /* |
---|
2 | * ---------------------------------------------------------------------------- |
---|
3 | * "THE BEER-WARE LICENSE" (Revision 42): |
---|
4 | * <phk@login.dknet.dk> wrote this file. As long as you retain this |
---|
5 | * notice you can do whatever you want with this stuff. If we meet some |
---|
6 | * day, and you think this stuff is worth it, you can buy me a beer in |
---|
7 | * return. Poul-Henning Kamp |
---|
8 | * ---------------------------------------------------------------------------- |
---|
9 | */ |
---|
10 | |
---|
11 | #include "includes.h" |
---|
12 | |
---|
13 | #if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) |
---|
14 | #include <openssl/md5.h> |
---|
15 | |
---|
16 | RCSID("$Id: md5crypt.c,v 1.1.1.2 2006-11-30 21:18:48 ghudson Exp $"); |
---|
17 | |
---|
18 | /* 0 ... 63 => ascii - 64 */ |
---|
19 | static unsigned char itoa64[] = |
---|
20 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
---|
21 | |
---|
22 | static char *magic = "$1$"; |
---|
23 | |
---|
24 | static char * |
---|
25 | to64(unsigned long v, int n) |
---|
26 | { |
---|
27 | static char buf[5]; |
---|
28 | char *s = buf; |
---|
29 | |
---|
30 | if (n > 4) |
---|
31 | return (NULL); |
---|
32 | |
---|
33 | memset(buf, '\0', sizeof(buf)); |
---|
34 | while (--n >= 0) { |
---|
35 | *s++ = itoa64[v&0x3f]; |
---|
36 | v >>= 6; |
---|
37 | } |
---|
38 | |
---|
39 | return (buf); |
---|
40 | } |
---|
41 | |
---|
42 | int |
---|
43 | is_md5_salt(const char *salt) |
---|
44 | { |
---|
45 | return (strncmp(salt, magic, strlen(magic)) == 0); |
---|
46 | } |
---|
47 | |
---|
48 | char * |
---|
49 | md5_crypt(const char *pw, const char *salt) |
---|
50 | { |
---|
51 | static char passwd[120], salt_copy[9], *p; |
---|
52 | static const char *sp, *ep; |
---|
53 | unsigned char final[16]; |
---|
54 | int sl, pl, i, j; |
---|
55 | MD5_CTX ctx, ctx1; |
---|
56 | unsigned long l; |
---|
57 | |
---|
58 | /* Refine the Salt first */ |
---|
59 | sp = salt; |
---|
60 | |
---|
61 | /* If it starts with the magic string, then skip that */ |
---|
62 | if(strncmp(sp, magic, strlen(magic)) == 0) |
---|
63 | sp += strlen(magic); |
---|
64 | |
---|
65 | /* It stops at the first '$', max 8 chars */ |
---|
66 | for (ep = sp; *ep != '$'; ep++) { |
---|
67 | if (*ep == '\0' || ep >= (sp + 8)) |
---|
68 | return (NULL); |
---|
69 | } |
---|
70 | |
---|
71 | /* get the length of the true salt */ |
---|
72 | sl = ep - sp; |
---|
73 | |
---|
74 | /* Stash the salt */ |
---|
75 | memcpy(salt_copy, sp, sl); |
---|
76 | salt_copy[sl] = '\0'; |
---|
77 | |
---|
78 | MD5_Init(&ctx); |
---|
79 | |
---|
80 | /* The password first, since that is what is most unknown */ |
---|
81 | MD5_Update(&ctx, pw, strlen(pw)); |
---|
82 | |
---|
83 | /* Then our magic string */ |
---|
84 | MD5_Update(&ctx, magic, strlen(magic)); |
---|
85 | |
---|
86 | /* Then the raw salt */ |
---|
87 | MD5_Update(&ctx, sp, sl); |
---|
88 | |
---|
89 | /* Then just as many characters of the MD5(pw, salt, pw) */ |
---|
90 | MD5_Init(&ctx1); |
---|
91 | MD5_Update(&ctx1, pw, strlen(pw)); |
---|
92 | MD5_Update(&ctx1, sp, sl); |
---|
93 | MD5_Update(&ctx1, pw, strlen(pw)); |
---|
94 | MD5_Final(final, &ctx1); |
---|
95 | |
---|
96 | for(pl = strlen(pw); pl > 0; pl -= 16) |
---|
97 | MD5_Update(&ctx, final, pl > 16 ? 16 : pl); |
---|
98 | |
---|
99 | /* Don't leave anything around in vm they could use. */ |
---|
100 | memset(final, '\0', sizeof final); |
---|
101 | |
---|
102 | /* Then something really weird... */ |
---|
103 | for (j = 0, i = strlen(pw); i != 0; i >>= 1) |
---|
104 | if (i & 1) |
---|
105 | MD5_Update(&ctx, final + j, 1); |
---|
106 | else |
---|
107 | MD5_Update(&ctx, pw + j, 1); |
---|
108 | |
---|
109 | /* Now make the output string */ |
---|
110 | snprintf(passwd, sizeof(passwd), "%s%s$", magic, salt_copy); |
---|
111 | |
---|
112 | MD5_Final(final, &ctx); |
---|
113 | |
---|
114 | /* |
---|
115 | * and now, just to make sure things don't run too fast |
---|
116 | * On a 60 Mhz Pentium this takes 34 msec, so you would |
---|
117 | * need 30 seconds to build a 1000 entry dictionary... |
---|
118 | */ |
---|
119 | for(i = 0; i < 1000; i++) { |
---|
120 | MD5_Init(&ctx1); |
---|
121 | if (i & 1) |
---|
122 | MD5_Update(&ctx1, pw, strlen(pw)); |
---|
123 | else |
---|
124 | MD5_Update(&ctx1, final, 16); |
---|
125 | |
---|
126 | if (i % 3) |
---|
127 | MD5_Update(&ctx1, sp, sl); |
---|
128 | |
---|
129 | if (i % 7) |
---|
130 | MD5_Update(&ctx1, pw, strlen(pw)); |
---|
131 | |
---|
132 | if (i & 1) |
---|
133 | MD5_Update(&ctx1, final, 16); |
---|
134 | else |
---|
135 | MD5_Update(&ctx1, pw, strlen(pw)); |
---|
136 | |
---|
137 | MD5_Final(final, &ctx1); |
---|
138 | } |
---|
139 | |
---|
140 | p = passwd + strlen(passwd); |
---|
141 | |
---|
142 | l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; |
---|
143 | strlcat(passwd, to64(l, 4), sizeof(passwd)); |
---|
144 | l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; |
---|
145 | strlcat(passwd, to64(l, 4), sizeof(passwd)); |
---|
146 | l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; |
---|
147 | strlcat(passwd, to64(l, 4), sizeof(passwd)); |
---|
148 | l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; |
---|
149 | strlcat(passwd, to64(l, 4), sizeof(passwd)); |
---|
150 | l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; |
---|
151 | strlcat(passwd, to64(l, 4), sizeof(passwd)); |
---|
152 | l = final[11] ; |
---|
153 | strlcat(passwd, to64(l, 2), sizeof(passwd)); |
---|
154 | |
---|
155 | /* Don't leave anything around in vm they could use. */ |
---|
156 | memset(final, 0, sizeof(final)); |
---|
157 | memset(salt_copy, 0, sizeof(salt_copy)); |
---|
158 | memset(&ctx, 0, sizeof(ctx)); |
---|
159 | memset(&ctx1, 0, sizeof(ctx1)); |
---|
160 | (void)to64(0, 4); |
---|
161 | |
---|
162 | return (passwd); |
---|
163 | } |
---|
164 | |
---|
165 | #endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */ |
---|