]>
Commit | Line | Data |
---|---|---|
c84142e8 UD |
1 | /* One way encryption based on MD5 sum. |
2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. | |
3 | This file is part of the GNU C Library. | |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Library General Public License as | |
8 | published by the Free Software Foundation; either version 2 of the | |
9 | License, or (at your option) any later version. | |
10 | ||
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Library General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Library General Public | |
17 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
18 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | Boston, MA 02111-1307, USA. */ | |
68dbb3a6 UD |
20 | |
21 | #include <errno.h> | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include <sys/param.h> | |
25 | ||
26 | #include "md5.h" | |
27 | ||
28 | ||
29 | /* Define our magic string to mark salt for MD5 "encryption" | |
30 | replacement. This is meant to be the same as for other MD5 based | |
31 | encryption implementations. */ | |
32 | static const char md5_salt_prefix[] = "$1$"; | |
33 | ||
34 | /* Table with characters for base64 transformation. */ | |
35 | static const char b64t[64] = | |
36 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
37 | ||
38 | ||
39 | /* Prototypes for local functions. */ | |
40 | extern char *md5_crypt_r __P ((const char *key, const char *salt, char *buffer, | |
41 | int buflen)); | |
42 | extern char *md5_crypt __P ((const char *key, const char *salt)); | |
43 | ||
44 | ||
45 | ||
46 | /* This entry point is equivalent to the `crypt' function in Unix | |
47 | libcs. */ | |
48 | char * | |
49 | md5_crypt_r (key, salt, buffer, buflen) | |
50 | const char *key; | |
51 | const char *salt; | |
52 | char *buffer; | |
53 | int buflen; | |
54 | { | |
55 | unsigned char alt_result[16]; | |
56 | struct md5_ctx ctx; | |
57 | struct md5_ctx alt_ctx; | |
58 | size_t salt_len; | |
59 | size_t key_len; | |
60 | size_t cnt; | |
61 | char *cp; | |
62 | ||
63 | /* Find beginning of salt string. The prefix should normally always | |
64 | be present. Just in case it is not. */ | |
65 | if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0) | |
66 | /* Skip salt prefix. */ | |
67 | salt += sizeof (md5_salt_prefix) - 1; | |
68 | ||
69 | salt_len = MIN (strcspn (salt, "$"), 8); | |
70 | key_len = strlen (key); | |
71 | ||
72 | /* Prepare for the real work. */ | |
73 | md5_init_ctx (&ctx); | |
74 | ||
75 | /* Add the key string. */ | |
76 | md5_process_bytes (key, key_len, &ctx); | |
77 | ||
78 | /* Because the SALT argument need not always have the salt prefix we | |
79 | add it separately. */ | |
80 | md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, &ctx); | |
81 | ||
82 | /* The last part is the salt string. This must be at most 8 | |
83 | characters and it ends at the first `$' character (for | |
84 | compatibility which existing solutions). */ | |
85 | md5_process_bytes (salt, salt_len, &ctx); | |
86 | ||
87 | ||
88 | /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The | |
89 | final result will be added to the first context. */ | |
90 | md5_init_ctx (&alt_ctx); | |
91 | ||
92 | /* Add key. */ | |
93 | md5_process_bytes (key, key_len, &alt_ctx); | |
94 | ||
95 | /* Add salt. */ | |
96 | md5_process_bytes (salt, salt_len, &alt_ctx); | |
97 | ||
98 | /* Add key again. */ | |
99 | md5_process_bytes (key, key_len, &alt_ctx); | |
100 | ||
101 | /* Now get result of this (16 bytes) and add it to the other | |
102 | context. */ | |
103 | md5_finish_ctx (&alt_ctx, alt_result); | |
104 | ||
105 | /* Add for any character in the key one byte of the alternate sum. */ | |
106 | for (cnt = key_len; cnt > 16; cnt -= 16) | |
107 | md5_process_bytes (alt_result, 16, &ctx); | |
108 | md5_process_bytes (alt_result, cnt, &ctx); | |
109 | ||
110 | /* For the following code we need a NUL byte. */ | |
111 | *alt_result = '\0'; | |
112 | ||
113 | /* The original implementation now does something weird: for every 1 | |
114 | bit in the key the first 0 is added to the buffer, for every 0 | |
115 | bit the first character of the key. This does not seem to be | |
116 | what was intended but we have to follow this to be compatible. */ | |
117 | for (cnt = key_len; cnt > 0; cnt >>= 1) | |
118 | md5_process_bytes ((cnt & 1) != 0 ? (const char *) alt_result : key, 1, | |
119 | &ctx); | |
120 | ||
121 | /* Create intermediate result. */ | |
122 | md5_finish_ctx (&ctx, alt_result); | |
123 | ||
124 | /* Now comes another weirdness. In fear of password crackers here | |
125 | comes a quite long loop which just processes the output of the | |
126 | previous round again. We cannot ignore this here. */ | |
127 | for (cnt = 0; cnt < 1000; ++cnt) | |
128 | { | |
129 | /* New context. */ | |
130 | md5_init_ctx (&ctx); | |
131 | ||
132 | /* Add key or last result. */ | |
133 | if ((cnt & 1) != 0) | |
134 | md5_process_bytes (key, key_len, &ctx); | |
135 | else | |
136 | md5_process_bytes (alt_result, 16, &ctx); | |
137 | ||
138 | /* Add salt for numbers not divisible by 3. */ | |
139 | if (cnt % 3 != 0) | |
140 | md5_process_bytes (salt, salt_len, &ctx); | |
141 | ||
142 | /* Add key for numbers not divisible by 7. */ | |
143 | if (cnt % 7 != 0) | |
144 | md5_process_bytes (key, key_len, &ctx); | |
145 | ||
146 | /* Add key or last result. */ | |
147 | if ((cnt & 1) != 0) | |
148 | md5_process_bytes (alt_result, 16, &ctx); | |
149 | else | |
150 | md5_process_bytes (key, key_len, &ctx); | |
151 | ||
152 | /* Create intermediate result. */ | |
153 | md5_finish_ctx (&ctx, alt_result); | |
154 | } | |
155 | ||
156 | /* Now we can construct the result string. It consists of three | |
157 | parts. */ | |
158 | cp = stpncpy (buffer, md5_salt_prefix, MAX (0, buflen)); | |
159 | buflen -= sizeof (md5_salt_prefix); | |
160 | ||
161 | cp = stpncpy (cp, salt, MIN ((size_t) buflen, salt_len)); | |
162 | buflen -= MIN ((size_t) buflen, salt_len); | |
163 | ||
164 | if (buflen > 0) | |
165 | { | |
166 | *cp++ = '$'; | |
167 | --buflen; | |
168 | } | |
169 | ||
170 | #define b64_from_24bit(B2, B1, B0, N) \ | |
171 | do { \ | |
172 | unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ | |
173 | int n = (N); \ | |
174 | while (n-- > 0 && buflen > 0) \ | |
175 | { \ | |
176 | *cp++ = b64t[w & 0x3f]; \ | |
177 | --buflen; \ | |
178 | w >>= 6; \ | |
179 | } \ | |
180 | } while (0) | |
181 | ||
182 | ||
183 | b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4); | |
184 | b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4); | |
185 | b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4); | |
186 | b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4); | |
187 | b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4); | |
188 | b64_from_24bit (0, 0, alt_result[11], 2); | |
189 | if (buflen <= 0) | |
190 | { | |
191 | __set_errno (ERANGE); | |
192 | buffer = NULL; | |
193 | } | |
194 | else | |
195 | *cp = '\0'; /* Terminate the string. */ | |
196 | ||
197 | /* Clear the buffer for the intermediate result so that people | |
198 | attaching to processes or reading core dumps cannot get any | |
199 | information. */ | |
200 | memset (alt_result, '\0', sizeof (alt_result)); | |
201 | ||
202 | return buffer; | |
203 | } | |
204 | ||
205 | ||
206 | char * | |
207 | md5_crypt (key, salt) | |
208 | const char *key; | |
209 | const char *salt; | |
210 | { | |
211 | /* We don't want to have an arbitrary limit in the size of the | |
212 | password. We can compute the size of the result in advance and | |
213 | so we can prepare the buffer we pass to `md5_crypt_r'. */ | |
214 | static char *buffer = NULL; | |
215 | static int buflen = 0; | |
216 | int needed = 3 + strlen (salt) + 1 + 26 + 1; | |
217 | ||
218 | if (buflen < needed) | |
219 | { | |
220 | buflen = needed; | |
221 | if ((buffer = realloc (buffer, buflen)) == NULL) | |
222 | return NULL; | |
223 | } | |
224 | ||
225 | return md5_crypt_r (key, salt, buffer, buflen); | |
226 | } |