setipv4sourcefilter: Avoid using alloca.
[glibc.git] / crypt / md5-crypt.c
blob4e4760545a0aa6afcff7fdfcf7c97f64ab834d3d
1 /* One way encryption based on MD5 sum.
2 Compatible with the behavior of MD5 crypt introduced in FreeBSD 2.0.
3 Copyright (C) 1996-2023 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/param.h>
26 #include "md5.h"
27 #include "crypt-private.h"
30 #ifdef USE_NSS
31 typedef int PRBool;
32 # include <hasht.h>
33 # include <nsslowhash.h>
35 # define md5_init_ctx(ctxp, nss_ctxp) \
36 do \
37 { \
38 if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgMD5)) \
39 == NULL)) \
40 { \
41 if (nss_ctx != NULL) \
42 NSSLOWHASH_Destroy (nss_ctx); \
43 if (nss_alt_ctx != NULL) \
44 NSSLOWHASH_Destroy (nss_alt_ctx); \
45 return NULL; \
46 } \
47 NSSLOWHASH_Begin (nss_ctxp); \
48 } \
49 while (0)
51 # define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
52 NSSLOWHASH_Update (nss_ctxp, (const unsigned char *) buf, len)
54 # define md5_finish_ctx(ctxp, nss_ctxp, result) \
55 do \
56 { \
57 unsigned int ret; \
58 NSSLOWHASH_End (nss_ctxp, result, &ret, sizeof (result)); \
59 assert (ret == sizeof (result)); \
60 NSSLOWHASH_Destroy (nss_ctxp); \
61 nss_ctxp = NULL; \
62 } \
63 while (0)
64 #else
65 # define md5_init_ctx(ctxp, nss_ctxp) \
66 __md5_init_ctx (ctxp)
68 # define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
69 __md5_process_bytes(buf, len, ctxp)
71 # define md5_finish_ctx(ctxp, nss_ctxp, result) \
72 __md5_finish_ctx (ctxp, result)
73 #endif
76 /* Define our magic string to mark salt for MD5 "encryption"
77 replacement. This is meant to be the same as for other MD5 based
78 encryption implementations. */
79 static const char md5_salt_prefix[] = "$1$";
82 /* Prototypes for local functions. */
83 extern char *__md5_crypt_r (const char *key, const char *salt,
84 char *buffer, int buflen);
85 extern char *__md5_crypt (const char *key, const char *salt);
88 /* This entry point is equivalent to the `crypt' function in Unix
89 libcs. */
90 char *
91 __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
93 unsigned char alt_result[16]
94 __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
95 size_t salt_len;
96 size_t key_len;
97 size_t cnt;
98 char *cp;
99 char *copied_key = NULL;
100 char *copied_salt = NULL;
101 char *free_key = NULL;
102 size_t alloca_used = 0;
104 /* Find beginning of salt string. The prefix should normally always
105 be present. Just in case it is not. */
106 if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
107 /* Skip salt prefix. */
108 salt += sizeof (md5_salt_prefix) - 1;
110 salt_len = MIN (strcspn (salt, "$"), 8);
111 key_len = strlen (key);
113 if (((uintptr_t) key) % __alignof__ (md5_uint32) != 0)
115 char *tmp;
117 if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32)))
118 tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
119 else
121 free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32));
122 if (tmp == NULL)
123 return NULL;
126 key = copied_key =
127 memcpy (tmp + __alignof__ (md5_uint32)
128 - ((uintptr_t) tmp) % __alignof__ (md5_uint32),
129 key, key_len);
130 assert (((uintptr_t) key) % __alignof__ (md5_uint32) == 0);
133 if (((uintptr_t) salt) % __alignof__ (md5_uint32) != 0)
135 char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
136 salt = copied_salt =
137 memcpy (tmp + __alignof__ (md5_uint32)
138 - ((uintptr_t) tmp) % __alignof__ (md5_uint32),
139 salt, salt_len);
140 assert (((uintptr_t) salt) % __alignof__ (md5_uint32) == 0);
143 #ifdef USE_NSS
144 /* Initialize libfreebl3. */
145 NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
146 if (nss_ictx == NULL)
148 free (free_key);
149 return NULL;
151 NSSLOWHASHContext *nss_ctx = NULL;
152 NSSLOWHASHContext *nss_alt_ctx = NULL;
153 #else
154 struct md5_ctx ctx;
155 struct md5_ctx alt_ctx;
156 #endif
158 /* Prepare for the real work. */
159 md5_init_ctx (&ctx, nss_ctx);
161 /* Add the key string. */
162 md5_process_bytes (key, key_len, &ctx, nss_ctx);
164 /* Because the SALT argument need not always have the salt prefix we
165 add it separately. */
166 md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
167 &ctx, nss_ctx);
169 /* The last part is the salt string. This must be at most 8
170 characters and it ends at the first `$' character (for
171 compatibility with existing implementations). */
172 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
175 /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The
176 final result will be added to the first context. */
177 md5_init_ctx (&alt_ctx, nss_alt_ctx);
179 /* Add key. */
180 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
182 /* Add salt. */
183 md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
185 /* Add key again. */
186 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
188 /* Now get result of this (16 bytes) and add it to the other
189 context. */
190 md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
192 /* Add for any character in the key one byte of the alternate sum. */
193 for (cnt = key_len; cnt > 16; cnt -= 16)
194 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
195 md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
197 /* For the following code we need a NUL byte. */
198 *alt_result = '\0';
200 /* The original implementation now does something weird: for every 1
201 bit in the key the first 0 is added to the buffer, for every 0
202 bit the first character of the key. This does not seem to be
203 what was intended but we have to follow this to be compatible. */
204 for (cnt = key_len; cnt > 0; cnt >>= 1)
205 md5_process_bytes ((cnt & 1) != 0
206 ? (const void *) alt_result : (const void *) key, 1,
207 &ctx, nss_ctx);
209 /* Create intermediate result. */
210 md5_finish_ctx (&ctx, nss_ctx, alt_result);
212 /* Now comes another weirdness. In fear of password crackers here
213 comes a quite long loop which just processes the output of the
214 previous round again. We cannot ignore this here. */
215 for (cnt = 0; cnt < 1000; ++cnt)
217 /* New context. */
218 md5_init_ctx (&ctx, nss_ctx);
220 /* Add key or last result. */
221 if ((cnt & 1) != 0)
222 md5_process_bytes (key, key_len, &ctx, nss_ctx);
223 else
224 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
226 /* Add salt for numbers not divisible by 3. */
227 if (cnt % 3 != 0)
228 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
230 /* Add key for numbers not divisible by 7. */
231 if (cnt % 7 != 0)
232 md5_process_bytes (key, key_len, &ctx, nss_ctx);
234 /* Add key or last result. */
235 if ((cnt & 1) != 0)
236 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
237 else
238 md5_process_bytes (key, key_len, &ctx, nss_ctx);
240 /* Create intermediate result. */
241 md5_finish_ctx (&ctx, nss_ctx, alt_result);
244 #ifdef USE_NSS
245 /* Free libfreebl3 resources. */
246 NSSLOW_Shutdown (nss_ictx);
247 #endif
249 /* Now we can construct the result string. It consists of three
250 parts. */
251 cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
252 buflen -= sizeof (md5_salt_prefix) - 1;
254 cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
255 buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
257 if (buflen > 0)
259 *cp++ = '$';
260 --buflen;
263 __b64_from_24bit (&cp, &buflen,
264 alt_result[0], alt_result[6], alt_result[12], 4);
265 __b64_from_24bit (&cp, &buflen,
266 alt_result[1], alt_result[7], alt_result[13], 4);
267 __b64_from_24bit (&cp, &buflen,
268 alt_result[2], alt_result[8], alt_result[14], 4);
269 __b64_from_24bit (&cp, &buflen,
270 alt_result[3], alt_result[9], alt_result[15], 4);
271 __b64_from_24bit (&cp, &buflen,
272 alt_result[4], alt_result[10], alt_result[5], 4);
273 __b64_from_24bit (&cp, &buflen,
274 0, 0, alt_result[11], 2);
275 if (buflen <= 0)
277 __set_errno (ERANGE);
278 buffer = NULL;
280 else
281 *cp = '\0'; /* Terminate the string. */
283 /* Clear the buffer for the intermediate result so that people
284 attaching to processes or reading core dumps cannot get any
285 information. We do it in this way to clear correct_words[]
286 inside the MD5 implementation as well. */
287 #ifndef USE_NSS
288 __md5_init_ctx (&ctx);
289 __md5_finish_ctx (&ctx, alt_result);
290 explicit_bzero (&ctx, sizeof (ctx));
291 explicit_bzero (&alt_ctx, sizeof (alt_ctx));
292 #endif
293 if (copied_key != NULL)
294 explicit_bzero (copied_key, key_len);
295 if (copied_salt != NULL)
296 explicit_bzero (copied_salt, salt_len);
298 free (free_key);
299 return buffer;
302 static char *buffer;
304 char *
305 __md5_crypt (const char *key, const char *salt)
307 /* We don't want to have an arbitrary limit in the size of the
308 password. We can compute the size of the result in advance and
309 so we can prepare the buffer we pass to `md5_crypt_r'. */
310 static int buflen;
311 int needed = 3 + strlen (salt) + 1 + 26 + 1;
313 if (buflen < needed)
315 char *new_buffer = (char *) realloc (buffer, needed);
316 if (new_buffer == NULL)
317 return NULL;
319 buffer = new_buffer;
320 buflen = needed;
323 return __md5_crypt_r (key, salt, buffer, buflen);
326 static void
327 __attribute__ ((__destructor__))
328 free_mem (void)
330 free (buffer);