]> git.ipfire.org Git - thirdparty/glibc.git/blame - crypt/md5-crypt.c
Update copyright dates with scripts/update-copyrights.
[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.
688903eb 3 Copyright (C) 1996-2018 Free Software Foundation, Inc.
c84142e8
UD
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6
7 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
c84142e8
UD
11
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 15 Lesser General Public License for more details.
c84142e8 16
41bdb6e2 17 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
18 License along with the GNU C Library; if not, see
19 <http://www.gnu.org/licenses/>. */
68dbb3a6 20
3248e3a3 21#include <assert.h>
68dbb3a6
UD
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/param.h>
26
27#include "md5.h"
8747cd03 28#include "crypt-private.h"
68dbb3a6
UD
29
30
ff886b82
UD
31#ifdef USE_NSS
32typedef int PRBool;
33# include <hasht.h>
34# include <nsslowhash.h>
35
36# define md5_init_ctx(ctxp, nss_ctxp) \
37 do \
38 { \
019324d0 39 if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgMD5)) \
ff886b82
UD
40 == NULL)) \
41 { \
42 if (nss_ctx != NULL) \
43 NSSLOWHASH_Destroy (nss_ctx); \
44 if (nss_alt_ctx != NULL) \
45 NSSLOWHASH_Destroy (nss_alt_ctx); \
46 return NULL; \
47 } \
48 NSSLOWHASH_Begin (nss_ctxp); \
49 } \
50 while (0)
51
52# define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
53 NSSLOWHASH_Update (nss_ctxp, (const unsigned char *) buf, len)
54
55# define md5_finish_ctx(ctxp, nss_ctxp, result) \
56 do \
57 { \
58 unsigned int ret; \
59 NSSLOWHASH_End (nss_ctxp, result, &ret, sizeof (result)); \
60 assert (ret == sizeof (result)); \
61 NSSLOWHASH_Destroy (nss_ctxp); \
62 nss_ctxp = NULL; \
63 } \
64 while (0)
65#else
66# define md5_init_ctx(ctxp, nss_ctxp) \
67 __md5_init_ctx (ctxp)
68
69# define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
70 __md5_process_bytes(buf, len, ctxp)
71
72# define md5_finish_ctx(ctxp, nss_ctxp, result) \
73 __md5_finish_ctx (ctxp, result)
74#endif
75
76
68dbb3a6
UD
77/* Define our magic string to mark salt for MD5 "encryption"
78 replacement. This is meant to be the same as for other MD5 based
79 encryption implementations. */
80static const char md5_salt_prefix[] = "$1$";
81
68dbb3a6
UD
82
83/* Prototypes for local functions. */
3248e3a3
UD
84extern char *__md5_crypt_r (const char *key, const char *salt,
85 char *buffer, int buflen);
86extern char *__md5_crypt (const char *key, const char *salt);
68dbb3a6
UD
87
88
89/* This entry point is equivalent to the `crypt' function in Unix
90 libcs. */
91char *
9dd346ff 92__md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
68dbb3a6 93{
3248e3a3
UD
94 unsigned char alt_result[16]
95 __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
68dbb3a6
UD
96 size_t salt_len;
97 size_t key_len;
98 size_t cnt;
99 char *cp;
5bef2820
UD
100 char *copied_key = NULL;
101 char *copied_salt = NULL;
b8dc394d
JL
102 char *free_key = NULL;
103 size_t alloca_used = 0;
68dbb3a6
UD
104
105 /* Find beginning of salt string. The prefix should normally always
106 be present. Just in case it is not. */
107 if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
108 /* Skip salt prefix. */
109 salt += sizeof (md5_salt_prefix) - 1;
110
111 salt_len = MIN (strcspn (salt, "$"), 8);
112 key_len = strlen (key);
113
3248e3a3
UD
114 if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
115 {
b8dc394d
JL
116 char *tmp;
117
118 if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32)))
119 tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
120 else
121 {
122 free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32));
123 if (tmp == NULL)
124 return NULL;
125 }
126
5bef2820
UD
127 key = copied_key =
128 memcpy (tmp + __alignof__ (md5_uint32)
129 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
130 key, key_len);
3248e3a3
UD
131 assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
132 }
133
134 if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
135 {
136 char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
5bef2820
UD
137 salt = copied_salt =
138 memcpy (tmp + __alignof__ (md5_uint32)
139 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
140 salt, salt_len);
3248e3a3
UD
141 assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
142 }
143
ff886b82
UD
144#ifdef USE_NSS
145 /* Initialize libfreebl3. */
146 NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
147 if (nss_ictx == NULL)
b8dc394d
JL
148 {
149 free (free_key);
150 return NULL;
151 }
ff886b82
UD
152 NSSLOWHASHContext *nss_ctx = NULL;
153 NSSLOWHASHContext *nss_alt_ctx = NULL;
154#else
155 struct md5_ctx ctx;
156 struct md5_ctx alt_ctx;
157#endif
158
68dbb3a6 159 /* Prepare for the real work. */
ff886b82 160 md5_init_ctx (&ctx, nss_ctx);
68dbb3a6
UD
161
162 /* Add the key string. */
ff886b82 163 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
164
165 /* Because the SALT argument need not always have the salt prefix we
166 add it separately. */
ff886b82
UD
167 md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
168 &ctx, nss_ctx);
68dbb3a6
UD
169
170 /* The last part is the salt string. This must be at most 8
171 characters and it ends at the first `$' character (for
ff0507a8 172 compatibility with existing implementations). */
ff886b82 173 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
68dbb3a6
UD
174
175
176 /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The
177 final result will be added to the first context. */
ff886b82 178 md5_init_ctx (&alt_ctx, nss_alt_ctx);
68dbb3a6
UD
179
180 /* Add key. */
ff886b82 181 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
182
183 /* Add salt. */
ff886b82 184 md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
185
186 /* Add key again. */
ff886b82 187 md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
68dbb3a6
UD
188
189 /* Now get result of this (16 bytes) and add it to the other
190 context. */
ff886b82 191 md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
68dbb3a6
UD
192
193 /* Add for any character in the key one byte of the alternate sum. */
194 for (cnt = key_len; cnt > 16; cnt -= 16)
ff886b82
UD
195 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
196 md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
68dbb3a6
UD
197
198 /* For the following code we need a NUL byte. */
199 *alt_result = '\0';
200
201 /* The original implementation now does something weird: for every 1
202 bit in the key the first 0 is added to the buffer, for every 0
203 bit the first character of the key. This does not seem to be
204 what was intended but we have to follow this to be compatible. */
205 for (cnt = key_len; cnt > 0; cnt >>= 1)
ff886b82
UD
206 md5_process_bytes ((cnt & 1) != 0
207 ? (const void *) alt_result : (const void *) key, 1,
208 &ctx, nss_ctx);
68dbb3a6
UD
209
210 /* Create intermediate result. */
ff886b82 211 md5_finish_ctx (&ctx, nss_ctx, alt_result);
68dbb3a6
UD
212
213 /* Now comes another weirdness. In fear of password crackers here
214 comes a quite long loop which just processes the output of the
215 previous round again. We cannot ignore this here. */
216 for (cnt = 0; cnt < 1000; ++cnt)
217 {
218 /* New context. */
ff886b82 219 md5_init_ctx (&ctx, nss_ctx);
68dbb3a6
UD
220
221 /* Add key or last result. */
222 if ((cnt & 1) != 0)
ff886b82 223 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6 224 else
ff886b82 225 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
68dbb3a6
UD
226
227 /* Add salt for numbers not divisible by 3. */
228 if (cnt % 3 != 0)
ff886b82 229 md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
68dbb3a6
UD
230
231 /* Add key for numbers not divisible by 7. */
232 if (cnt % 7 != 0)
ff886b82 233 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
234
235 /* Add key or last result. */
236 if ((cnt & 1) != 0)
ff886b82 237 md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
68dbb3a6 238 else
ff886b82 239 md5_process_bytes (key, key_len, &ctx, nss_ctx);
68dbb3a6
UD
240
241 /* Create intermediate result. */
ff886b82 242 md5_finish_ctx (&ctx, nss_ctx, alt_result);
68dbb3a6
UD
243 }
244
ff886b82
UD
245#ifdef USE_NSS
246 /* Free libfreebl3 resources. */
247 NSSLOW_Shutdown (nss_ictx);
248#endif
249
68dbb3a6
UD
250 /* Now we can construct the result string. It consists of three
251 parts. */
b13927da 252 cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
cb2391e1 253 buflen -= sizeof (md5_salt_prefix) - 1;
68dbb3a6 254
cb2391e1
UD
255 cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
256 buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
68dbb3a6
UD
257
258 if (buflen > 0)
259 {
260 *cp++ = '$';
261 --buflen;
262 }
263
8747cd03
KS
264 __b64_from_24bit (&cp, &buflen,
265 alt_result[0], alt_result[6], alt_result[12], 4);
266 __b64_from_24bit (&cp, &buflen,
267 alt_result[1], alt_result[7], alt_result[13], 4);
268 __b64_from_24bit (&cp, &buflen,
269 alt_result[2], alt_result[8], alt_result[14], 4);
270 __b64_from_24bit (&cp, &buflen,
271 alt_result[3], alt_result[9], alt_result[15], 4);
272 __b64_from_24bit (&cp, &buflen,
273 alt_result[4], alt_result[10], alt_result[5], 4);
274 __b64_from_24bit (&cp, &buflen,
275 0, 0, alt_result[11], 2);
68dbb3a6
UD
276 if (buflen <= 0)
277 {
278 __set_errno (ERANGE);
279 buffer = NULL;
280 }
281 else
282 *cp = '\0'; /* Terminate the string. */
283
284 /* Clear the buffer for the intermediate result so that people
285 attaching to processes or reading core dumps cannot get any
11b34882
UD
286 information. We do it in this way to clear correct_words[]
287 inside the MD5 implementation as well. */
ff886b82 288#ifndef USE_NSS
11b34882
UD
289 __md5_init_ctx (&ctx);
290 __md5_finish_ctx (&ctx, alt_result);
ea1bd74d
ZW
291 explicit_bzero (&ctx, sizeof (ctx));
292 explicit_bzero (&alt_ctx, sizeof (alt_ctx));
ff886b82 293#endif
5bef2820 294 if (copied_key != NULL)
ea1bd74d 295 explicit_bzero (copied_key, key_len);
5bef2820 296 if (copied_salt != NULL)
ea1bd74d 297 explicit_bzero (copied_salt, salt_len);
68dbb3a6 298
b8dc394d 299 free (free_key);
68dbb3a6
UD
300 return buffer;
301}
302
c877418f
RM
303#ifndef _LIBC
304# define libc_freeres_ptr(decl) decl
305#endif
306libc_freeres_ptr (static char *buffer);
b8fd5502 307
68dbb3a6 308char *
a9b5d2ee 309__md5_crypt (const char *key, const char *salt)
68dbb3a6
UD
310{
311 /* We don't want to have an arbitrary limit in the size of the
312 password. We can compute the size of the result in advance and
313 so we can prepare the buffer we pass to `md5_crypt_r'. */
b8fd5502 314 static int buflen;
68dbb3a6
UD
315 int needed = 3 + strlen (salt) + 1 + 26 + 1;
316
317 if (buflen < needed)
318 {
f05a089d 319 char *new_buffer = (char *) realloc (buffer, needed);
d1dddedf 320 if (new_buffer == NULL)
68dbb3a6 321 return NULL;
d1dddedf
UD
322
323 buffer = new_buffer;
f05a089d 324 buflen = needed;
68dbb3a6
UD
325 }
326
b13927da 327 return __md5_crypt_r (key, salt, buffer, buflen);
68dbb3a6 328}
b8fd5502 329
c877418f 330#ifndef _LIBC
b8fd5502 331static void
0c571040 332__attribute__ ((__destructor__))
b8fd5502
UD
333free_mem (void)
334{
335 free (buffer);
336}
c877418f 337#endif