Back to index

glibc  2.9
sha512-crypt.c
Go to the documentation of this file.
00001 /* One way encryption based on SHA512 sum.
00002    Copyright (C) 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <assert.h>
00022 #include <errno.h>
00023 #include <stdbool.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <sys/param.h>
00027 
00028 #include "sha512.h"
00029 
00030 
00031 /* Define our magic string to mark salt for SHA512 "encryption"
00032    replacement.  */
00033 static const char sha512_salt_prefix[] = "$6$";
00034 
00035 /* Prefix for optional rounds specification.  */
00036 static const char sha512_rounds_prefix[] = "rounds=";
00037 
00038 /* Maximum salt string length.  */
00039 #define SALT_LEN_MAX 16
00040 /* Default number of rounds if not explicitly specified.  */
00041 #define ROUNDS_DEFAULT 5000
00042 /* Minimum number of rounds.  */
00043 #define ROUNDS_MIN 1000
00044 /* Maximum number of rounds.  */
00045 #define ROUNDS_MAX 999999999
00046 
00047 /* Table with characters for base64 transformation.  */
00048 static const char b64t[64] =
00049 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
00050 
00051 
00052 /* Prototypes for local functions.  */
00053 extern char *__sha512_crypt_r (const char *key, const char *salt,
00054                             char *buffer, int buflen);
00055 extern char *__sha512_crypt (const char *key, const char *salt);
00056 
00057 
00058 char *
00059 __sha512_crypt_r (key, salt, buffer, buflen)
00060      const char *key;
00061      const char *salt;
00062      char *buffer;
00063      int buflen;
00064 {
00065   unsigned char alt_result[64]
00066     __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
00067   unsigned char temp_result[64]
00068     __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
00069   struct sha512_ctx ctx;
00070   struct sha512_ctx alt_ctx;
00071   size_t salt_len;
00072   size_t key_len;
00073   size_t cnt;
00074   char *cp;
00075   char *copied_key = NULL;
00076   char *copied_salt = NULL;
00077   char *p_bytes;
00078   char *s_bytes;
00079   /* Default number of rounds.  */
00080   size_t rounds = ROUNDS_DEFAULT;
00081   bool rounds_custom = false;
00082 
00083   /* Find beginning of salt string.  The prefix should normally always
00084      be present.  Just in case it is not.  */
00085   if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
00086     /* Skip salt prefix.  */
00087     salt += sizeof (sha512_salt_prefix) - 1;
00088 
00089   if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1)
00090       == 0)
00091     {
00092       const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
00093       char *endp;
00094       unsigned long int srounds = strtoul (num, &endp, 10);
00095       if (*endp == '$')
00096        {
00097          salt = endp + 1;
00098          rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
00099          rounds_custom = true;
00100        }
00101     }
00102 
00103   salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
00104   key_len = strlen (key);
00105 
00106   if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
00107     {
00108       char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
00109       key = copied_key =
00110        memcpy (tmp + __alignof__ (uint64_t)
00111               - (tmp - (char *) 0) % __alignof__ (uint64_t),
00112               key, key_len);
00113       assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0);
00114     }
00115 
00116   if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
00117     {
00118       char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
00119       salt = copied_salt =
00120        memcpy (tmp + __alignof__ (uint64_t)
00121               - (tmp - (char *) 0) % __alignof__ (uint64_t),
00122               salt, salt_len);
00123       assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0);
00124     }
00125 
00126   /* Prepare for the real work.  */
00127   __sha512_init_ctx (&ctx);
00128 
00129   /* Add the key string.  */
00130   __sha512_process_bytes (key, key_len, &ctx);
00131 
00132   /* The last part is the salt string.  This must be at most 16
00133      characters and it ends at the first `$' character.  */
00134   __sha512_process_bytes (salt, salt_len, &ctx);
00135 
00136 
00137   /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.  The
00138      final result will be added to the first context.  */
00139   __sha512_init_ctx (&alt_ctx);
00140 
00141   /* Add key.  */
00142   __sha512_process_bytes (key, key_len, &alt_ctx);
00143 
00144   /* Add salt.  */
00145   __sha512_process_bytes (salt, salt_len, &alt_ctx);
00146 
00147   /* Add key again.  */
00148   __sha512_process_bytes (key, key_len, &alt_ctx);
00149 
00150   /* Now get result of this (64 bytes) and add it to the other
00151      context.  */
00152   __sha512_finish_ctx (&alt_ctx, alt_result);
00153 
00154   /* Add for any character in the key one byte of the alternate sum.  */
00155   for (cnt = key_len; cnt > 64; cnt -= 64)
00156     __sha512_process_bytes (alt_result, 64, &ctx);
00157   __sha512_process_bytes (alt_result, cnt, &ctx);
00158 
00159   /* Take the binary representation of the length of the key and for every
00160      1 add the alternate sum, for every 0 the key.  */
00161   for (cnt = key_len; cnt > 0; cnt >>= 1)
00162     if ((cnt & 1) != 0)
00163       __sha512_process_bytes (alt_result, 64, &ctx);
00164     else
00165       __sha512_process_bytes (key, key_len, &ctx);
00166 
00167   /* Create intermediate result.  */
00168   __sha512_finish_ctx (&ctx, alt_result);
00169 
00170   /* Start computation of P byte sequence.  */
00171   __sha512_init_ctx (&alt_ctx);
00172 
00173   /* For every character in the password add the entire password.  */
00174   for (cnt = 0; cnt < key_len; ++cnt)
00175     __sha512_process_bytes (key, key_len, &alt_ctx);
00176 
00177   /* Finish the digest.  */
00178   __sha512_finish_ctx (&alt_ctx, temp_result);
00179 
00180   /* Create byte sequence P.  */
00181   cp = p_bytes = alloca (key_len);
00182   for (cnt = key_len; cnt >= 64; cnt -= 64)
00183     cp = mempcpy (cp, temp_result, 64);
00184   memcpy (cp, temp_result, cnt);
00185 
00186   /* Start computation of S byte sequence.  */
00187   __sha512_init_ctx (&alt_ctx);
00188 
00189   /* For every character in the password add the entire password.  */
00190   for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
00191     __sha512_process_bytes (salt, salt_len, &alt_ctx);
00192 
00193   /* Finish the digest.  */
00194   __sha512_finish_ctx (&alt_ctx, temp_result);
00195 
00196   /* Create byte sequence S.  */
00197   cp = s_bytes = alloca (salt_len);
00198   for (cnt = salt_len; cnt >= 64; cnt -= 64)
00199     cp = mempcpy (cp, temp_result, 64);
00200   memcpy (cp, temp_result, cnt);
00201 
00202   /* Repeatedly run the collected hash value through SHA512 to burn
00203      CPU cycles.  */
00204   for (cnt = 0; cnt < rounds; ++cnt)
00205     {
00206       /* New context.  */
00207       __sha512_init_ctx (&ctx);
00208 
00209       /* Add key or last result.  */
00210       if ((cnt & 1) != 0)
00211        __sha512_process_bytes (p_bytes, key_len, &ctx);
00212       else
00213        __sha512_process_bytes (alt_result, 64, &ctx);
00214 
00215       /* Add salt for numbers not divisible by 3.  */
00216       if (cnt % 3 != 0)
00217        __sha512_process_bytes (s_bytes, salt_len, &ctx);
00218 
00219       /* Add key for numbers not divisible by 7.  */
00220       if (cnt % 7 != 0)
00221        __sha512_process_bytes (p_bytes, key_len, &ctx);
00222 
00223       /* Add key or last result.  */
00224       if ((cnt & 1) != 0)
00225        __sha512_process_bytes (alt_result, 64, &ctx);
00226       else
00227        __sha512_process_bytes (p_bytes, key_len, &ctx);
00228 
00229       /* Create intermediate result.  */
00230       __sha512_finish_ctx (&ctx, alt_result);
00231     }
00232 
00233   /* Now we can construct the result string.  It consists of three
00234      parts.  */
00235   cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
00236   buflen -= sizeof (sha512_salt_prefix) - 1;
00237 
00238   if (rounds_custom)
00239     {
00240       int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
00241                      sha512_rounds_prefix, rounds);
00242       cp += n;
00243       buflen -= n;
00244     }
00245 
00246   cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
00247   buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
00248 
00249   if (buflen > 0)
00250     {
00251       *cp++ = '$';
00252       --buflen;
00253     }
00254 
00255 #define b64_from_24bit(B2, B1, B0, N)                                       \
00256   do {                                                               \
00257     unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);                     \
00258     int n = (N);                                                     \
00259     while (n-- > 0 && buflen > 0)                                    \
00260       {                                                                     \
00261        *cp++ = b64t[w & 0x3f];                                              \
00262        --buflen;                                                     \
00263        w >>= 6;                                                      \
00264       }                                                                     \
00265   } while (0)
00266 
00267   b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
00268   b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
00269   b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
00270   b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
00271   b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
00272   b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
00273   b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
00274   b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
00275   b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
00276   b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
00277   b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
00278   b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
00279   b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
00280   b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
00281   b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
00282   b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
00283   b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
00284   b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
00285   b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
00286   b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
00287   b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
00288   b64_from_24bit (0, 0, alt_result[63], 2);
00289 
00290   if (buflen <= 0)
00291     {
00292       __set_errno (ERANGE);
00293       buffer = NULL;
00294     }
00295   else
00296     *cp = '\0';             /* Terminate the string.  */
00297 
00298   /* Clear the buffer for the intermediate result so that people
00299      attaching to processes or reading core dumps cannot get any
00300      information.  We do it in this way to clear correct_words[]
00301      inside the SHA512 implementation as well.  */
00302   __sha512_init_ctx (&ctx);
00303   __sha512_finish_ctx (&ctx, alt_result);
00304   memset (temp_result, '\0', sizeof (temp_result));
00305   memset (p_bytes, '\0', key_len);
00306   memset (s_bytes, '\0', salt_len);
00307   memset (&ctx, '\0', sizeof (ctx));
00308   memset (&alt_ctx, '\0', sizeof (alt_ctx));
00309   if (copied_key != NULL)
00310     memset (copied_key, '\0', key_len);
00311   if (copied_salt != NULL)
00312     memset (copied_salt, '\0', salt_len);
00313 
00314   return buffer;
00315 }
00316 
00317 #ifndef _LIBC
00318 # define libc_freeres_ptr(decl) decl
00319 #endif
00320 libc_freeres_ptr (static char *buffer);
00321 
00322 /* This entry point is equivalent to the `crypt' function in Unix
00323    libcs.  */
00324 char *
00325 __sha512_crypt (const char *key, const char *salt)
00326 {
00327   /* We don't want to have an arbitrary limit in the size of the
00328      password.  We can compute an upper bound for the size of the
00329      result in advance and so we can prepare the buffer we pass to
00330      `sha512_crypt_r'.  */
00331   static int buflen;
00332   int needed = (sizeof (sha512_salt_prefix) - 1
00333               + sizeof (sha512_rounds_prefix) + 9 + 1
00334               + strlen (salt) + 1 + 86 + 1);
00335 
00336   if (buflen < needed)
00337     {
00338       char *new_buffer = (char *) realloc (buffer, needed);
00339       if (new_buffer == NULL)
00340        return NULL;
00341 
00342       buffer = new_buffer;
00343       buflen = needed;
00344     }
00345 
00346   return __sha512_crypt_r (key, salt, buffer, buflen);
00347 }
00348 
00349 #ifndef _LIBC
00350 static void
00351 __attribute__ ((__destructor__))
00352 free_mem (void)
00353 {
00354   free (buffer);
00355 }
00356 #endif