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