Smack: add the execute lable to ldconfig
[platform/upstream/glibc.git] / crypt / md5-crypt.c
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-2015 Free Software Foundation, Inc.
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
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.
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
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/param.h>
26
27 #include "md5.h"
28 #include "crypt-private.h"
29
30
31 #ifdef USE_NSS
32 typedef int PRBool;
33 # include <hasht.h>
34 # include <nsslowhash.h>
35
36 # define md5_init_ctx(ctxp, nss_ctxp) \
37   do                                                                          \
38     {                                                                         \
39       if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgMD5))         \
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
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.  */
80 static const char md5_salt_prefix[] = "$1$";
81
82
83 /* Prototypes for local functions.  */
84 extern char *__md5_crypt_r (const char *key, const char *salt,
85                             char *buffer, int buflen);
86 extern char *__md5_crypt (const char *key, const char *salt);
87
88
89 /* This entry point is equivalent to the `crypt' function in Unix
90    libcs.  */
91 char *
92 __md5_crypt_r (key, salt, buffer, buflen)
93      const char *key;
94      const char *salt;
95      char *buffer;
96      int buflen;
97 {
98   unsigned char alt_result[16]
99     __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
100   size_t salt_len;
101   size_t key_len;
102   size_t cnt;
103   char *cp;
104   char *copied_key = NULL;
105   char *copied_salt = NULL;
106   char *free_key = NULL;
107   size_t alloca_used = 0;
108
109   /* Find beginning of salt string.  The prefix should normally always
110      be present.  Just in case it is not.  */
111   if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
112     /* Skip salt prefix.  */
113     salt += sizeof (md5_salt_prefix) - 1;
114
115   salt_len = MIN (strcspn (salt, "$"), 8);
116   key_len = strlen (key);
117
118   if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
119     {
120       char *tmp;
121
122       if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32)))
123         tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
124       else
125         {
126           free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32));
127           if (tmp == NULL)
128             return NULL;
129         }
130
131       key = copied_key =
132         memcpy (tmp + __alignof__ (md5_uint32)
133                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
134                 key, key_len);
135       assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
136     }
137
138   if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
139     {
140       char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
141       salt = copied_salt =
142         memcpy (tmp + __alignof__ (md5_uint32)
143                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
144                 salt, salt_len);
145       assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
146     }
147
148 #ifdef USE_NSS
149   /* Initialize libfreebl3.  */
150   NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
151   if (nss_ictx == NULL)
152     {
153       free (free_key);
154       return NULL;
155     }
156   NSSLOWHASHContext *nss_ctx = NULL;
157   NSSLOWHASHContext *nss_alt_ctx = NULL;
158 #else
159   struct md5_ctx ctx;
160   struct md5_ctx alt_ctx;
161 #endif
162
163   /* Prepare for the real work.  */
164   md5_init_ctx (&ctx, nss_ctx);
165
166   /* Add the key string.  */
167   md5_process_bytes (key, key_len, &ctx, nss_ctx);
168
169   /* Because the SALT argument need not always have the salt prefix we
170      add it separately.  */
171   md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
172                      &ctx, nss_ctx);
173
174   /* The last part is the salt string.  This must be at most 8
175      characters and it ends at the first `$' character (for
176      compatibility with existing implementations).  */
177   md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
178
179
180   /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
181      final result will be added to the first context.  */
182   md5_init_ctx (&alt_ctx, nss_alt_ctx);
183
184   /* Add key.  */
185   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
186
187   /* Add salt.  */
188   md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
189
190   /* Add key again.  */
191   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
192
193   /* Now get result of this (16 bytes) and add it to the other
194      context.  */
195   md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
196
197   /* Add for any character in the key one byte of the alternate sum.  */
198   for (cnt = key_len; cnt > 16; cnt -= 16)
199     md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
200   md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
201
202   /* For the following code we need a NUL byte.  */
203   *alt_result = '\0';
204
205   /* The original implementation now does something weird: for every 1
206      bit in the key the first 0 is added to the buffer, for every 0
207      bit the first character of the key.  This does not seem to be
208      what was intended but we have to follow this to be compatible.  */
209   for (cnt = key_len; cnt > 0; cnt >>= 1)
210     md5_process_bytes ((cnt & 1) != 0
211                        ? (const void *) alt_result : (const void *) key, 1,
212                        &ctx, nss_ctx);
213
214   /* Create intermediate result.  */
215   md5_finish_ctx (&ctx, nss_ctx, alt_result);
216
217   /* Now comes another weirdness.  In fear of password crackers here
218      comes a quite long loop which just processes the output of the
219      previous round again.  We cannot ignore this here.  */
220   for (cnt = 0; cnt < 1000; ++cnt)
221     {
222       /* New context.  */
223       md5_init_ctx (&ctx, nss_ctx);
224
225       /* Add key or last result.  */
226       if ((cnt & 1) != 0)
227         md5_process_bytes (key, key_len, &ctx, nss_ctx);
228       else
229         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
230
231       /* Add salt for numbers not divisible by 3.  */
232       if (cnt % 3 != 0)
233         md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
234
235       /* Add key for numbers not divisible by 7.  */
236       if (cnt % 7 != 0)
237         md5_process_bytes (key, key_len, &ctx, nss_ctx);
238
239       /* Add key or last result.  */
240       if ((cnt & 1) != 0)
241         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
242       else
243         md5_process_bytes (key, key_len, &ctx, nss_ctx);
244
245       /* Create intermediate result.  */
246       md5_finish_ctx (&ctx, nss_ctx, alt_result);
247     }
248
249 #ifdef USE_NSS
250   /* Free libfreebl3 resources. */
251   NSSLOW_Shutdown (nss_ictx);
252 #endif
253
254   /* Now we can construct the result string.  It consists of three
255      parts.  */
256   cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
257   buflen -= sizeof (md5_salt_prefix) - 1;
258
259   cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
260   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
261
262   if (buflen > 0)
263     {
264       *cp++ = '$';
265       --buflen;
266     }
267
268   __b64_from_24bit (&cp, &buflen,
269                     alt_result[0], alt_result[6], alt_result[12], 4);
270   __b64_from_24bit (&cp, &buflen,
271                     alt_result[1], alt_result[7], alt_result[13], 4);
272   __b64_from_24bit (&cp, &buflen,
273                     alt_result[2], alt_result[8], alt_result[14], 4);
274   __b64_from_24bit (&cp, &buflen,
275                     alt_result[3], alt_result[9], alt_result[15], 4);
276   __b64_from_24bit (&cp, &buflen,
277                     alt_result[4], alt_result[10], alt_result[5], 4);
278   __b64_from_24bit (&cp, &buflen,
279                     0, 0, alt_result[11], 2);
280   if (buflen <= 0)
281     {
282       __set_errno (ERANGE);
283       buffer = NULL;
284     }
285   else
286     *cp = '\0';         /* Terminate the string.  */
287
288   /* Clear the buffer for the intermediate result so that people
289      attaching to processes or reading core dumps cannot get any
290      information.  We do it in this way to clear correct_words[]
291      inside the MD5 implementation as well.  */
292 #ifndef USE_NSS
293   __md5_init_ctx (&ctx);
294   __md5_finish_ctx (&ctx, alt_result);
295   memset (&ctx, '\0', sizeof (ctx));
296   memset (&alt_ctx, '\0', sizeof (alt_ctx));
297 #endif
298   if (copied_key != NULL)
299     memset (copied_key, '\0', key_len);
300   if (copied_salt != NULL)
301     memset (copied_salt, '\0', salt_len);
302
303   free (free_key);
304   return buffer;
305 }
306
307 #ifndef _LIBC
308 # define libc_freeres_ptr(decl) decl
309 #endif
310 libc_freeres_ptr (static char *buffer);
311
312 char *
313 __md5_crypt (const char *key, const char *salt)
314 {
315   /* We don't want to have an arbitrary limit in the size of the
316      password.  We can compute the size of the result in advance and
317      so we can prepare the buffer we pass to `md5_crypt_r'.  */
318   static int buflen;
319   int needed = 3 + strlen (salt) + 1 + 26 + 1;
320
321   if (buflen < needed)
322     {
323       char *new_buffer = (char *) realloc (buffer, needed);
324       if (new_buffer == NULL)
325         return NULL;
326
327       buffer = new_buffer;
328       buflen = needed;
329     }
330
331   return __md5_crypt_r (key, salt, buffer, buflen);
332 }
333
334 #ifndef _LIBC
335 static void
336 __attribute__ ((__destructor__))
337 free_mem (void)
338 {
339   free (buffer);
340 }
341 #endif