Replace FSF snail mail address with URLs.
[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, 1997, 1999, 2000, 2001, 2002, 2004, 2009
4    Free Software Foundation, Inc.
5    This file is part of the GNU C Library.
6    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
7
8    The GNU C Library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2.1 of the License, or (at your option) any later version.
12
13    The GNU C Library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the GNU C Library; if not, see
20    <http://www.gnu.org/licenses/>.  */
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/param.h>
27
28 #include "md5.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 /* Table with characters for base64 transformation.  */
83 static const char b64t[64] =
84 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
85
86
87 /* Prototypes for local functions.  */
88 extern char *__md5_crypt_r (const char *key, const char *salt,
89                             char *buffer, int buflen);
90 extern char *__md5_crypt (const char *key, const char *salt);
91
92
93 /* This entry point is equivalent to the `crypt' function in Unix
94    libcs.  */
95 char *
96 __md5_crypt_r (key, salt, buffer, buflen)
97      const char *key;
98      const char *salt;
99      char *buffer;
100      int buflen;
101 {
102   unsigned char alt_result[16]
103     __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
104   size_t salt_len;
105   size_t key_len;
106   size_t cnt;
107   char *cp;
108   char *copied_key = NULL;
109   char *copied_salt = NULL;
110
111   /* Find beginning of salt string.  The prefix should normally always
112      be present.  Just in case it is not.  */
113   if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
114     /* Skip salt prefix.  */
115     salt += sizeof (md5_salt_prefix) - 1;
116
117   salt_len = MIN (strcspn (salt, "$"), 8);
118   key_len = strlen (key);
119
120   if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
121     {
122       char *tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
123       key = copied_key =
124         memcpy (tmp + __alignof__ (md5_uint32)
125                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
126                 key, key_len);
127       assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
128     }
129
130   if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
131     {
132       char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
133       salt = copied_salt =
134         memcpy (tmp + __alignof__ (md5_uint32)
135                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
136                 salt, salt_len);
137       assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
138     }
139
140 #ifdef USE_NSS
141   /* Initialize libfreebl3.  */
142   NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
143   if (nss_ictx == NULL)
144     return NULL;
145   NSSLOWHASHContext *nss_ctx = NULL;
146   NSSLOWHASHContext *nss_alt_ctx = NULL;
147 #else
148   struct md5_ctx ctx;
149   struct md5_ctx alt_ctx;
150 #endif
151
152   /* Prepare for the real work.  */
153   md5_init_ctx (&ctx, nss_ctx);
154
155   /* Add the key string.  */
156   md5_process_bytes (key, key_len, &ctx, nss_ctx);
157
158   /* Because the SALT argument need not always have the salt prefix we
159      add it separately.  */
160   md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
161                      &ctx, nss_ctx);
162
163   /* The last part is the salt string.  This must be at most 8
164      characters and it ends at the first `$' character (for
165      compatibility with existing implementations).  */
166   md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
167
168
169   /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
170      final result will be added to the first context.  */
171   md5_init_ctx (&alt_ctx, nss_alt_ctx);
172
173   /* Add key.  */
174   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
175
176   /* Add salt.  */
177   md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
178
179   /* Add key again.  */
180   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
181
182   /* Now get result of this (16 bytes) and add it to the other
183      context.  */
184   md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
185
186   /* Add for any character in the key one byte of the alternate sum.  */
187   for (cnt = key_len; cnt > 16; cnt -= 16)
188     md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
189   md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
190
191   /* For the following code we need a NUL byte.  */
192   *alt_result = '\0';
193
194   /* The original implementation now does something weird: for every 1
195      bit in the key the first 0 is added to the buffer, for every 0
196      bit the first character of the key.  This does not seem to be
197      what was intended but we have to follow this to be compatible.  */
198   for (cnt = key_len; cnt > 0; cnt >>= 1)
199     md5_process_bytes ((cnt & 1) != 0
200                        ? (const void *) alt_result : (const void *) key, 1,
201                        &ctx, nss_ctx);
202
203   /* Create intermediate result.  */
204   md5_finish_ctx (&ctx, nss_ctx, alt_result);
205
206   /* Now comes another weirdness.  In fear of password crackers here
207      comes a quite long loop which just processes the output of the
208      previous round again.  We cannot ignore this here.  */
209   for (cnt = 0; cnt < 1000; ++cnt)
210     {
211       /* New context.  */
212       md5_init_ctx (&ctx, nss_ctx);
213
214       /* Add key or last result.  */
215       if ((cnt & 1) != 0)
216         md5_process_bytes (key, key_len, &ctx, nss_ctx);
217       else
218         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
219
220       /* Add salt for numbers not divisible by 3.  */
221       if (cnt % 3 != 0)
222         md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
223
224       /* Add key for numbers not divisible by 7.  */
225       if (cnt % 7 != 0)
226         md5_process_bytes (key, key_len, &ctx, nss_ctx);
227
228       /* Add key or last result.  */
229       if ((cnt & 1) != 0)
230         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
231       else
232         md5_process_bytes (key, key_len, &ctx, nss_ctx);
233
234       /* Create intermediate result.  */
235       md5_finish_ctx (&ctx, nss_ctx, alt_result);
236     }
237
238 #ifdef USE_NSS
239   /* Free libfreebl3 resources. */
240   NSSLOW_Shutdown (nss_ictx);
241 #endif
242
243   /* Now we can construct the result string.  It consists of three
244      parts.  */
245   cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
246   buflen -= sizeof (md5_salt_prefix) - 1;
247
248   cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
249   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
250
251   if (buflen > 0)
252     {
253       *cp++ = '$';
254       --buflen;
255     }
256
257   void b64_from_24bit (unsigned int b2, unsigned int b1, unsigned int b0,
258                        int n)
259   {
260     unsigned int w = (b2 << 16) | (b1 << 8) | b0;
261     while (n-- > 0 && buflen > 0)
262       {
263         *cp++ = b64t[w & 0x3f];
264         --buflen;
265         w >>= 6;
266       }
267   }
268
269   b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
270   b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
271   b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
272   b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
273   b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
274   b64_from_24bit (0, 0, alt_result[11], 2);
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
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   memset (&ctx, '\0', sizeof (ctx));
291   memset (&alt_ctx, '\0', sizeof (alt_ctx));
292 #endif
293   if (copied_key != NULL)
294     memset (copied_key, '\0', key_len);
295   if (copied_salt != NULL)
296     memset (copied_salt, '\0', salt_len);
297
298   return buffer;
299 }
300
301 #ifndef _LIBC
302 # define libc_freeres_ptr(decl) decl
303 #endif
304 libc_freeres_ptr (static char *buffer);
305
306 char *
307 __md5_crypt (const char *key, const char *salt)
308 {
309   /* We don't want to have an arbitrary limit in the size of the
310      password.  We can compute the size of the result in advance and
311      so we can prepare the buffer we pass to `md5_crypt_r'.  */
312   static int buflen;
313   int needed = 3 + strlen (salt) + 1 + 26 + 1;
314
315   if (buflen < needed)
316     {
317       char *new_buffer = (char *) realloc (buffer, needed);
318       if (new_buffer == NULL)
319         return NULL;
320
321       buffer = new_buffer;
322       buflen = needed;
323     }
324
325   return __md5_crypt_r (key, salt, buffer, buflen);
326 }
327
328 #ifndef _LIBC
329 static void
330 __attribute__ ((__destructor__))
331 free_mem (void)
332 {
333   free (buffer);
334 }
335 #endif