chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.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, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307 USA.  */
22
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/param.h>
28
29 #include "md5.h"
30
31
32 #ifdef USE_NSS
33 typedef int PRBool;
34 # include <hasht.h>
35 # include <nsslowhash.h>
36
37 # define md5_init_ctx(ctxp, nss_ctxp) \
38   do                                                                          \
39     {                                                                         \
40       if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgMD5))         \
41            == NULL))                                                          \
42         {                                                                     \
43           if (nss_ctx != NULL)                                                \
44             NSSLOWHASH_Destroy (nss_ctx);                                     \
45           if (nss_alt_ctx != NULL)                                            \
46             NSSLOWHASH_Destroy (nss_alt_ctx);                                 \
47           return NULL;                                                        \
48         }                                                                     \
49       NSSLOWHASH_Begin (nss_ctxp);                                            \
50     }                                                                         \
51   while (0)
52
53 # define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
54   NSSLOWHASH_Update (nss_ctxp, (const unsigned char *) buf, len)
55
56 # define md5_finish_ctx(ctxp, nss_ctxp, result) \
57   do                                                                          \
58     {                                                                         \
59       unsigned int ret;                                                       \
60       NSSLOWHASH_End (nss_ctxp, result, &ret, sizeof (result));               \
61       assert (ret == sizeof (result));                                        \
62       NSSLOWHASH_Destroy (nss_ctxp);                                          \
63       nss_ctxp = NULL;                                                        \
64     }                                                                         \
65   while (0)
66 #else
67 # define md5_init_ctx(ctxp, nss_ctxp) \
68   __md5_init_ctx (ctxp)
69
70 # define md5_process_bytes(buf, len, ctxp, nss_ctxp) \
71   __md5_process_bytes(buf, len, ctxp)
72
73 # define md5_finish_ctx(ctxp, nss_ctxp, result) \
74   __md5_finish_ctx (ctxp, result)
75 #endif
76
77
78 /* Define our magic string to mark salt for MD5 "encryption"
79    replacement.  This is meant to be the same as for other MD5 based
80    encryption implementations.  */
81 static const char md5_salt_prefix[] = "$1$";
82
83 /* Table with characters for base64 transformation.  */
84 static const char b64t[64] =
85 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
86
87
88 /* Prototypes for local functions.  */
89 extern char *__md5_crypt_r (const char *key, const char *salt,
90                             char *buffer, int buflen);
91 extern char *__md5_crypt (const char *key, const char *salt);
92
93
94 /* This entry point is equivalent to the `crypt' function in Unix
95    libcs.  */
96 char *
97 __md5_crypt_r (key, salt, buffer, buflen)
98      const char *key;
99      const char *salt;
100      char *buffer;
101      int buflen;
102 {
103   unsigned char alt_result[16]
104     __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
105   size_t salt_len;
106   size_t key_len;
107   size_t cnt;
108   char *cp;
109   char *copied_key = NULL;
110   char *copied_salt = NULL;
111
112   /* Find beginning of salt string.  The prefix should normally always
113      be present.  Just in case it is not.  */
114   if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
115     /* Skip salt prefix.  */
116     salt += sizeof (md5_salt_prefix) - 1;
117
118   salt_len = MIN (strcspn (salt, "$"), 8);
119   key_len = strlen (key);
120
121   if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
122     {
123       char *tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
124       key = copied_key =
125         memcpy (tmp + __alignof__ (md5_uint32)
126                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
127                 key, key_len);
128       assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
129     }
130
131   if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
132     {
133       char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
134       salt = copied_salt =
135         memcpy (tmp + __alignof__ (md5_uint32)
136                 - (tmp - (char *) 0) % __alignof__ (md5_uint32),
137                 salt, salt_len);
138       assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
139     }
140
141 #ifdef USE_NSS
142   /* Initialize libfreebl3.  */
143   NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
144   if (nss_ictx == NULL)
145     return NULL;
146   NSSLOWHASHContext *nss_ctx = NULL;
147   NSSLOWHASHContext *nss_alt_ctx = NULL;
148 #else
149   struct md5_ctx ctx;
150   struct md5_ctx alt_ctx;
151 #endif
152
153   /* Prepare for the real work.  */
154   md5_init_ctx (&ctx, nss_ctx);
155
156   /* Add the key string.  */
157   md5_process_bytes (key, key_len, &ctx, nss_ctx);
158
159   /* Because the SALT argument need not always have the salt prefix we
160      add it separately.  */
161   md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
162                      &ctx, nss_ctx);
163
164   /* The last part is the salt string.  This must be at most 8
165      characters and it ends at the first `$' character (for
166      compatibility with existing implementations).  */
167   md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
168
169
170   /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
171      final result will be added to the first context.  */
172   md5_init_ctx (&alt_ctx, nss_alt_ctx);
173
174   /* Add key.  */
175   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
176
177   /* Add salt.  */
178   md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
179
180   /* Add key again.  */
181   md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
182
183   /* Now get result of this (16 bytes) and add it to the other
184      context.  */
185   md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
186
187   /* Add for any character in the key one byte of the alternate sum.  */
188   for (cnt = key_len; cnt > 16; cnt -= 16)
189     md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
190   md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);
191
192   /* For the following code we need a NUL byte.  */
193   *alt_result = '\0';
194
195   /* The original implementation now does something weird: for every 1
196      bit in the key the first 0 is added to the buffer, for every 0
197      bit the first character of the key.  This does not seem to be
198      what was intended but we have to follow this to be compatible.  */
199   for (cnt = key_len; cnt > 0; cnt >>= 1)
200     md5_process_bytes ((cnt & 1) != 0
201                        ? (const void *) alt_result : (const void *) key, 1,
202                        &ctx, nss_ctx);
203
204   /* Create intermediate result.  */
205   md5_finish_ctx (&ctx, nss_ctx, alt_result);
206
207   /* Now comes another weirdness.  In fear of password crackers here
208      comes a quite long loop which just processes the output of the
209      previous round again.  We cannot ignore this here.  */
210   for (cnt = 0; cnt < 1000; ++cnt)
211     {
212       /* New context.  */
213       md5_init_ctx (&ctx, nss_ctx);
214
215       /* Add key or last result.  */
216       if ((cnt & 1) != 0)
217         md5_process_bytes (key, key_len, &ctx, nss_ctx);
218       else
219         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
220
221       /* Add salt for numbers not divisible by 3.  */
222       if (cnt % 3 != 0)
223         md5_process_bytes (salt, salt_len, &ctx, nss_ctx);
224
225       /* Add key for numbers not divisible by 7.  */
226       if (cnt % 7 != 0)
227         md5_process_bytes (key, key_len, &ctx, nss_ctx);
228
229       /* Add key or last result.  */
230       if ((cnt & 1) != 0)
231         md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
232       else
233         md5_process_bytes (key, key_len, &ctx, nss_ctx);
234
235       /* Create intermediate result.  */
236       md5_finish_ctx (&ctx, nss_ctx, alt_result);
237     }
238
239 #ifdef USE_NSS
240   /* Free libfreebl3 resources. */
241   NSSLOW_Shutdown (nss_ictx);
242 #endif
243
244   /* Now we can construct the result string.  It consists of three
245      parts.  */
246   cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
247   buflen -= sizeof (md5_salt_prefix) - 1;
248
249   cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
250   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
251
252   if (buflen > 0)
253     {
254       *cp++ = '$';
255       --buflen;
256     }
257
258   void b64_from_24bit (unsigned int b2, unsigned int b1, unsigned int b0,
259                        int n)
260   {
261     unsigned int w = (b2 << 16) | (b1 << 8) | b0;
262     while (n-- > 0 && buflen > 0)
263       {
264         *cp++ = b64t[w & 0x3f];
265         --buflen;
266         w >>= 6;
267       }
268   }
269
270   b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
271   b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
272   b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
273   b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
274   b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
275   b64_from_24bit (0, 0, alt_result[11], 2);
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
286      information.  We do it in this way to clear correct_words[]
287      inside the MD5 implementation as well.  */
288 #ifndef USE_NSS
289   __md5_init_ctx (&ctx);
290   __md5_finish_ctx (&ctx, alt_result);
291   memset (&ctx, '\0', sizeof (ctx));
292   memset (&alt_ctx, '\0', sizeof (alt_ctx));
293 #endif
294   if (copied_key != NULL)
295     memset (copied_key, '\0', key_len);
296   if (copied_salt != NULL)
297     memset (copied_salt, '\0', salt_len);
298
299   return buffer;
300 }
301
302 #ifndef _LIBC
303 # define libc_freeres_ptr(decl) decl
304 #endif
305 libc_freeres_ptr (static char *buffer);
306
307 char *
308 __md5_crypt (const char *key, const char *salt)
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'.  */
313   static int buflen;
314   int needed = 3 + strlen (salt) + 1 + 26 + 1;
315
316   if (buflen < needed)
317     {
318       char *new_buffer = (char *) realloc (buffer, needed);
319       if (new_buffer == NULL)
320         return NULL;
321
322       buffer = new_buffer;
323       buflen = needed;
324     }
325
326   return __md5_crypt_r (key, salt, buffer, buflen);
327 }
328
329 #ifndef _LIBC
330 static void
331 __attribute__ ((__destructor__))
332 free_mem (void)
333 {
334   free (buffer);
335 }
336 #endif