]> git.ipfire.org Git - thirdparty/glibc.git/blame - crypt/md5-crypt.c
posix/glob.c: update from gnulib
[thirdparty/glibc.git] / crypt / md5-crypt.c
CommitLineData
c84142e8 1/* One way encryption based on MD5 sum.
4483f2c0 2 Compatible with the behavior of MD5 crypt introduced in FreeBSD 2.0.
581c785b 3 Copyright (C) 1996-2022 Free Software Foundation, Inc.
c84142e8 4 This file is part of the GNU C Library.
c84142e8
UD
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
c84142e8
UD
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
41bdb6e2 14 Lesser General Public License for more details.
c84142e8 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6 17 License along with the GNU C Library; if not, see
5a82c748 18 <https://www.gnu.org/licenses/>. */
68dbb3a6 19
3248e3a3 20#include <assert.h>
68dbb3a6
UD
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/param.h>
25
26#include "md5.h"
8747cd03 27#include "crypt-private.h"
68dbb3a6
UD
28
29
ff886b82
UD
30#ifdef USE_NSS
31typedef int PRBool;
32# include <hasht.h>
33# include <nsslowhash.h>
34
35# define md5_init_ctx(ctxp, nss_ctxp) \
36 do \
37 { \
019324d0 38 if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgMD5)) \
ff886b82
UD
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)
50
51# define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
52 NSSLOWHASH_Update (nss_ctxp, (const unsigned char *) buf, len)
53
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)
67
68# define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
69 __md5_process_bytes(buf, len, ctxp)
70
71# define md5_finish_ctx(ctxp, nss_ctxp, result) \
72 __md5_finish_ctx (ctxp, result)
73#endif
74
75
68dbb3a6
UD
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. */
79static const char md5_salt_prefix[] = "$1$";
80
68dbb3a6
UD
81
82/* Prototypes for local functions. */
3248e3a3
UD
83extern char *__md5_crypt_r (const char *key, const char *salt,
84 char *buffer, int buflen);
85extern char *__md5_crypt (const char *key, const char *salt);
68dbb3a6
UD
86
87
88/* This entry point is equivalent to the `crypt' function in Unix
89 libcs. */
90char *
9dd346ff 91__md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
68dbb3a6 92{
3248e3a3
UD
93 unsigned char alt_result[16]
94 __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
68dbb3a6
UD
95 size_t salt_len;
96 size_t key_len;
97 size_t cnt;
98 char *cp;
5bef2820
UD
99 char *copied_key = NULL;
100 char *copied_salt = NULL;
b8dc394d
JL
101 char *free_key = NULL;
102 size_t alloca_used = 0;
68dbb3a6
UD
103
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;
109
110 salt_len = MIN (strcspn (salt, "$"), 8);
111 key_len = strlen (key);
112
3248e3a3
UD
113 if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
114 {
b8dc394d
JL
115 char *tmp;
116
117 if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32)))
118 tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
119 else
120 {
121 free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32));
122 if (tmp == NULL)
123 return NULL;
124 }
125
5bef2820
UD
126 key = copied_key =
127 memcpy (tmp + __alignof__ (md5_uint32)
128 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
129 key, key_len);
3248e3a3
UD
130 assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
131 }
132
133 if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
134 {
135 char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
5bef2820
UD
136 salt = copied_salt =
137 memcpy (tmp + __alignof__ (md5_uint32)
138 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
139 salt, salt_len);
3248e3a3
UD
140 assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
141 }
142
ff886b82
UD
143#ifdef USE_NSS
144 /* Initialize libfreebl3. */
145 NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
146 if (nss_ictx == NULL)
b8dc394d
JL
147 {
148 free (free_key);
149 return NULL;
150 }
ff886b82
UD
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
157
68dbb3a6 158 /* Prepare for the real work. */
ff886b82 159 md5_init_ctx (&ctx, nss_ctx);
68dbb3a6
UD
160
161 /* Add the key string. */
ff886b82 162 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
163
164 /* Because the SALT argument need not always have the salt prefix we
165 add it separately. */
ff886b82
UD
166 md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
167 &ctx, nss_ctx);
68dbb3a6
UD
168
169 /* The last part is the salt string. This must be at most 8
170 characters and it ends at the first `$' character (for
ff0507a8 171 compatibility with existing implementations). */
ff886b82 172 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
68dbb3a6
UD
173
174
175 /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The
176 final result will be added to the first context. */
ff886b82 177 md5_init_ctx (&alt_ctx, nss_alt_ctx);
68dbb3a6
UD
178
179 /* Add key. */
ff886b82 180 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
181
182 /* Add salt. */
ff886b82 183 md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
184
185 /* Add key again. */
ff886b82 186 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
187
188 /* Now get result of this (16 bytes) and add it to the other
189 context. */
ff886b82 190 md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
68dbb3a6
UD
191
192 /* Add for any character in the key one byte of the alternate sum. */
193 for (cnt = key_len; cnt > 16; cnt -= 16)
ff886b82
UD
194 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
195 md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
68dbb3a6
UD
196
197 /* For the following code we need a NUL byte. */
198 *alt_result = '\0';
199
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)
ff886b82
UD
205 md5_process_bytes ((cnt & 1) != 0
206 ? (const void *) alt_result : (const void *) key, 1,
207 &ctx, nss_ctx);
68dbb3a6
UD
208
209 /* Create intermediate result. */
ff886b82 210 md5_finish_ctx (&ctx, nss_ctx, alt_result);
68dbb3a6
UD
211
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)
216 {
217 /* New context. */
ff886b82 218 md5_init_ctx (&ctx, nss_ctx);
68dbb3a6
UD
219
220 /* Add key or last result. */
221 if ((cnt & 1) != 0)
ff886b82 222 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6 223 else
ff886b82 224 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
68dbb3a6
UD
225
226 /* Add salt for numbers not divisible by 3. */
227 if (cnt % 3 != 0)
ff886b82 228 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
68dbb3a6
UD
229
230 /* Add key for numbers not divisible by 7. */
231 if (cnt % 7 != 0)
ff886b82 232 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
233
234 /* Add key or last result. */
235 if ((cnt & 1) != 0)
ff886b82 236 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
68dbb3a6 237 else
ff886b82 238 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
239
240 /* Create intermediate result. */
ff886b82 241 md5_finish_ctx (&ctx, nss_ctx, alt_result);
68dbb3a6
UD
242 }
243
ff886b82
UD
244#ifdef USE_NSS
245 /* Free libfreebl3 resources. */
246 NSSLOW_Shutdown (nss_ictx);
247#endif
248
68dbb3a6
UD
249 /* Now we can construct the result string. It consists of three
250 parts. */
b13927da 251 cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
cb2391e1 252 buflen -= sizeof (md5_salt_prefix) - 1;
68dbb3a6 253
cb2391e1
UD
254 cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
255 buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
68dbb3a6
UD
256
257 if (buflen > 0)
258 {
259 *cp++ = '$';
260 --buflen;
261 }
262
8747cd03
KS
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);
68dbb3a6
UD
275 if (buflen <= 0)
276 {
277 __set_errno (ERANGE);
278 buffer = NULL;
279 }
280 else
281 *cp = '\0'; /* Terminate the string. */
282
283 /* Clear the buffer for the intermediate result so that people
284 attaching to processes or reading core dumps cannot get any
11b34882
UD
285 information. We do it in this way to clear correct_words[]
286 inside the MD5 implementation as well. */
ff886b82 287#ifndef USE_NSS
11b34882
UD
288 __md5_init_ctx (&ctx);
289 __md5_finish_ctx (&ctx, alt_result);
ea1bd74d
ZW
290 explicit_bzero (&ctx, sizeof (ctx));
291 explicit_bzero (&alt_ctx, sizeof (alt_ctx));
ff886b82 292#endif
5bef2820 293 if (copied_key != NULL)
ea1bd74d 294 explicit_bzero (copied_key, key_len);
5bef2820 295 if (copied_salt != NULL)
ea1bd74d 296 explicit_bzero (copied_salt, salt_len);
68dbb3a6 297
b8dc394d 298 free (free_key);
68dbb3a6
UD
299 return buffer;
300}
301
c877418f
RM
302#ifndef _LIBC
303# define libc_freeres_ptr(decl) decl
304#endif
305libc_freeres_ptr (static char *buffer);
b8fd5502 306
68dbb3a6 307char *
a9b5d2ee 308__md5_crypt (const char *key, const char *salt)
68dbb3a6
UD
309{
310 /* We don't want to have an arbitrary limit in the size of the
311 password. We can compute the size of the result in advance and
312 so we can prepare the buffer we pass to `md5_crypt_r'. */
b8fd5502 313 static int buflen;
68dbb3a6
UD
314 int needed = 3 + strlen (salt) + 1 + 26 + 1;
315
316 if (buflen < needed)
317 {
f05a089d 318 char *new_buffer = (char *) realloc (buffer, needed);
d1dddedf 319 if (new_buffer == NULL)
68dbb3a6 320 return NULL;
d1dddedf
UD
321
322 buffer = new_buffer;
f05a089d 323 buflen = needed;
68dbb3a6
UD
324 }
325
b13927da 326 return __md5_crypt_r (key, salt, buffer, buflen);
68dbb3a6 327}
b8fd5502 328
c877418f 329#ifndef _LIBC
b8fd5502 330static void
0c571040 331__attribute__ ((__destructor__))
b8fd5502
UD
332free_mem (void)
333{
334 free (buffer);
335}
c877418f 336#endif