Back to index

glibc  2.9
md5-crypt.c
Go to the documentation of this file.
00001 /* One way encryption based on MD5 sum.
00002    Compatible with the behavior of MD5 crypt introduced in FreeBSD 2.0.
00003    Copyright (C) 1996, 1997, 1999, 2000, 2001, 2002, 2004
00004    Free Software Foundation, Inc.
00005    This file is part of the GNU C Library.
00006    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00007 
00008    The GNU C Library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Lesser General Public
00010    License as published by the Free Software Foundation; either
00011    version 2.1 of the License, or (at your option) any later version.
00012 
00013    The GNU C Library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Lesser General Public License for more details.
00017 
00018    You should have received a copy of the GNU Lesser General Public
00019    License along with the GNU C Library; if not, write to the Free
00020    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00021    02111-1307 USA.  */
00022 
00023 #include <assert.h>
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <sys/param.h>
00028 
00029 #include "md5.h"
00030 
00031 
00032 /* Define our magic string to mark salt for MD5 "encryption"
00033    replacement.  This is meant to be the same as for other MD5 based
00034    encryption implementations.  */
00035 static const char md5_salt_prefix[] = "$1$";
00036 
00037 /* Table with characters for base64 transformation.  */
00038 static const char b64t[64] =
00039 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00040 
00041 
00042 /* Prototypes for local functions.  */
00043 extern char *__md5_crypt_r (const char *key, const char *salt,
00044                          char *buffer, int buflen);
00045 extern char *__md5_crypt (const char *key, const char *salt);
00046 
00047 
00048 /* This entry point is equivalent to the `crypt' function in Unix
00049    libcs.  */
00050 char *
00051 __md5_crypt_r (key, salt, buffer, buflen)
00052      const char *key;
00053      const char *salt;
00054      char *buffer;
00055      int buflen;
00056 {
00057   unsigned char alt_result[16]
00058     __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
00059   struct md5_ctx ctx;
00060   struct md5_ctx alt_ctx;
00061   size_t salt_len;
00062   size_t key_len;
00063   size_t cnt;
00064   char *cp;
00065   char *copied_key = NULL;
00066   char *copied_salt = NULL;
00067 
00068   /* Find beginning of salt string.  The prefix should normally always
00069      be present.  Just in case it is not.  */
00070   if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
00071     /* Skip salt prefix.  */
00072     salt += sizeof (md5_salt_prefix) - 1;
00073 
00074   salt_len = MIN (strcspn (salt, "$"), 8);
00075   key_len = strlen (key);
00076 
00077   if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
00078     {
00079       char *tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
00080       key = copied_key =
00081        memcpy (tmp + __alignof__ (md5_uint32)
00082               - (tmp - (char *) 0) % __alignof__ (md5_uint32),
00083               key, key_len);
00084       assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
00085     }
00086 
00087   if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
00088     {
00089       char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
00090       salt = copied_salt =
00091        memcpy (tmp + __alignof__ (md5_uint32)
00092               - (tmp - (char *) 0) % __alignof__ (md5_uint32),
00093               salt, salt_len);
00094       assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
00095     }
00096 
00097   /* Prepare for the real work.  */
00098   __md5_init_ctx (&ctx);
00099 
00100   /* Add the key string.  */
00101   __md5_process_bytes (key, key_len, &ctx);
00102 
00103   /* Because the SALT argument need not always have the salt prefix we
00104      add it separately.  */
00105   __md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, &ctx);
00106 
00107   /* The last part is the salt string.  This must be at most 8
00108      characters and it ends at the first `$' character (for
00109      compatibility with existing implementations).  */
00110   __md5_process_bytes (salt, salt_len, &ctx);
00111 
00112 
00113   /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
00114      final result will be added to the first context.  */
00115   __md5_init_ctx (&alt_ctx);
00116 
00117   /* Add key.  */
00118   __md5_process_bytes (key, key_len, &alt_ctx);
00119 
00120   /* Add salt.  */
00121   __md5_process_bytes (salt, salt_len, &alt_ctx);
00122 
00123   /* Add key again.  */
00124   __md5_process_bytes (key, key_len, &alt_ctx);
00125 
00126   /* Now get result of this (16 bytes) and add it to the other
00127      context.  */
00128   __md5_finish_ctx (&alt_ctx, alt_result);
00129 
00130   /* Add for any character in the key one byte of the alternate sum.  */
00131   for (cnt = key_len; cnt > 16; cnt -= 16)
00132     __md5_process_bytes (alt_result, 16, &ctx);
00133   __md5_process_bytes (alt_result, cnt, &ctx);
00134 
00135   /* For the following code we need a NUL byte.  */
00136   *alt_result = '\0';
00137 
00138   /* The original implementation now does something weird: for every 1
00139      bit in the key the first 0 is added to the buffer, for every 0
00140      bit the first character of the key.  This does not seem to be
00141      what was intended but we have to follow this to be compatible.  */
00142   for (cnt = key_len; cnt > 0; cnt >>= 1)
00143     __md5_process_bytes ((cnt & 1) != 0 ? (const char *) alt_result : key, 1,
00144                       &ctx);
00145 
00146   /* Create intermediate result.  */
00147   __md5_finish_ctx (&ctx, alt_result);
00148 
00149   /* Now comes another weirdness.  In fear of password crackers here
00150      comes a quite long loop which just processes the output of the
00151      previous round again.  We cannot ignore this here.  */
00152   for (cnt = 0; cnt < 1000; ++cnt)
00153     {
00154       /* New context.  */
00155       __md5_init_ctx (&ctx);
00156 
00157       /* Add key or last result.  */
00158       if ((cnt & 1) != 0)
00159        __md5_process_bytes (key, key_len, &ctx);
00160       else
00161        __md5_process_bytes (alt_result, 16, &ctx);
00162 
00163       /* Add salt for numbers not divisible by 3.  */
00164       if (cnt % 3 != 0)
00165        __md5_process_bytes (salt, salt_len, &ctx);
00166 
00167       /* Add key for numbers not divisible by 7.  */
00168       if (cnt % 7 != 0)
00169        __md5_process_bytes (key, key_len, &ctx);
00170 
00171       /* Add key or last result.  */
00172       if ((cnt & 1) != 0)
00173        __md5_process_bytes (alt_result, 16, &ctx);
00174       else
00175        __md5_process_bytes (key, key_len, &ctx);
00176 
00177       /* Create intermediate result.  */
00178       __md5_finish_ctx (&ctx, alt_result);
00179     }
00180 
00181   /* Now we can construct the result string.  It consists of three
00182      parts.  */
00183   cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
00184   buflen -= sizeof (md5_salt_prefix) - 1;
00185 
00186   cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
00187   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
00188 
00189   if (buflen > 0)
00190     {
00191       *cp++ = '$';
00192       --buflen;
00193     }
00194 
00195 #define b64_from_24bit(B2, B1, B0, N)                                       \
00196   do {                                                               \
00197     unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);                     \
00198     int n = (N);                                                     \
00199     while (n-- > 0 && buflen > 0)                                    \
00200       {                                                                     \
00201        *cp++ = b64t[w & 0x3f];                                              \
00202        --buflen;                                                     \
00203        w >>= 6;                                                      \
00204       }                                                                     \
00205   } while (0)
00206 
00207 
00208   b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
00209   b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
00210   b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
00211   b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
00212   b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
00213   b64_from_24bit (0, 0, alt_result[11], 2);
00214   if (buflen <= 0)
00215     {
00216       __set_errno (ERANGE);
00217       buffer = NULL;
00218     }
00219   else
00220     *cp = '\0';             /* Terminate the string.  */
00221 
00222   /* Clear the buffer for the intermediate result so that people
00223      attaching to processes or reading core dumps cannot get any
00224      information.  We do it in this way to clear correct_words[]
00225      inside the MD5 implementation as well.  */
00226   __md5_init_ctx (&ctx);
00227   __md5_finish_ctx (&ctx, alt_result);
00228   memset (&ctx, '\0', sizeof (ctx));
00229   memset (&alt_ctx, '\0', sizeof (alt_ctx));
00230   if (copied_key != NULL)
00231     memset (copied_key, '\0', key_len);
00232   if (copied_salt != NULL)
00233     memset (copied_salt, '\0', salt_len);
00234 
00235   return buffer;
00236 }
00237 
00238 #ifndef _LIBC
00239 # define libc_freeres_ptr(decl) decl
00240 #endif
00241 libc_freeres_ptr (static char *buffer);
00242 
00243 char *
00244 __md5_crypt (const char *key, const char *salt)
00245 {
00246   /* We don't want to have an arbitrary limit in the size of the
00247      password.  We can compute the size of the result in advance and
00248      so we can prepare the buffer we pass to `md5_crypt_r'.  */
00249   static int buflen;
00250   int needed = 3 + strlen (salt) + 1 + 26 + 1;
00251 
00252   if (buflen < needed)
00253     {
00254       char *new_buffer = (char *) realloc (buffer, needed);
00255       if (new_buffer == NULL)
00256        return NULL;
00257 
00258       buffer = new_buffer;
00259       buflen = needed;
00260     }
00261 
00262   return __md5_crypt_r (key, salt, buffer, buflen);
00263 }
00264 
00265 #ifndef _LIBC
00266 static void
00267 __attribute__ ((__destructor__))
00268 free_mem (void)
00269 {
00270   free (buffer);
00271 }
00272 #endif