LCOV - code coverage report
Current view: top level - util/crypto/nss - nss_sha512crypt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 132 166 79.5 %
Date: 2016-06-29 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* This file is based on the work of Ulrich Drepper
       2             :  * (http://people.redhat.com/drepper/SHA-crypt.txt). I have replaced the
       3             :  * included SHA512 implementation by calls to NSS
       4             :  * (http://www.mozilla.org/projects/security/pki/nss/).
       5             :  *
       6             :  *  Sumit Bose <sbose@redhat.com>
       7             :  */
       8             : /* SHA512-based Unix crypt implementation.
       9             :    Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>.  */
      10             : 
      11             : #include "config.h"
      12             : 
      13             : #include <errno.h>
      14             : #include <limits.h>
      15             : #include <stdbool.h>
      16             : #include <stdint.h>
      17             : #include <stdio.h>
      18             : #include <stdlib.h>
      19             : #include <string.h>
      20             : #include <sys/param.h>
      21             : #include <sys/types.h>
      22             : 
      23             : #include "util/util.h"
      24             : #include "util/sss_endian.h"
      25             : #include "util/crypto/nss/nss_util.h"
      26             : 
      27             : #include <prinit.h>
      28             : #include <nss.h>
      29             : #include <sechash.h>
      30             : #include <pk11func.h>
      31             : 
      32             : /* Define our magic string to mark salt for SHA512 "encryption" replacement. */
      33             : const char sha512_salt_prefix[] = "$6$";
      34             : #define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1)
      35             : 
      36             : /* Prefix for optional rounds specification. */
      37             : const char sha512_rounds_prefix[] = "rounds=";
      38             : #define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1)
      39             : 
      40             : #define SALT_LEN_MAX 16
      41             : #define ROUNDS_DEFAULT 5000
      42             : #define ROUNDS_MIN 1000
      43             : #define ROUNDS_MAX 999999999
      44             : 
      45             : /* Table with characters for base64 transformation.  */
      46             : const char b64t[64] =
      47             :     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      48             : 
      49             : /* base64 conversion function */
      50         956 : static inline void b64_from_24bit(char **dest, size_t *len, size_t n,
      51             :                                   uint8_t b2, uint8_t b1, uint8_t b0)
      52             : {
      53             :     uint32_t w;
      54             :     size_t i;
      55             : 
      56         956 :     if (*len < n) n = *len;
      57             : 
      58         956 :     w = (b2 << 16) | (b1 << 8) | b0;
      59        4700 :     for (i = 0; i < n; i++) {
      60        3744 :         (*dest)[i] = b64t[w & 0x3f];
      61        3744 :         w >>= 6;
      62             :     }
      63             : 
      64         956 :     *len -= i;
      65         956 :     *dest += i;
      66         956 : }
      67             : 
      68             : #define PTR_2_INT(x) ((x) - ((__typeof__ (x)) NULL))
      69             : #define ALIGN64 __alignof__(uint64_t)
      70             : 
      71          40 : static int sha512_crypt_r(const char *key,
      72             :                           const char *salt,
      73             :                           char *buffer, size_t buflen)
      74             : {
      75             :     unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64)));
      76             :     unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64)));
      77          40 :     size_t rounds = ROUNDS_DEFAULT;
      78          40 :     bool rounds_custom = false;
      79          40 :     HASHContext *alt_ctx = NULL;
      80          40 :     HASHContext *ctx = NULL;
      81             :     size_t salt_len;
      82             :     size_t key_len;
      83             :     size_t cnt;
      84          40 :     char *copied_salt = NULL;
      85          40 :     char *copied_key = NULL;
      86          40 :     char *p_bytes = NULL;
      87          40 :     char *s_bytes = NULL;
      88             :     int p1, p2, p3, pt, n;
      89             :     unsigned int part;
      90             :     char *cp, *tmp;
      91             :     int ret;
      92             : 
      93             :     /* Find beginning of salt string. The prefix should normally always be
      94             :      * present. Just in case it is not. */
      95          40 :     if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
      96             :         /* Skip salt prefix.  */
      97          21 :         salt += SALT_PREF_SIZE;
      98             :     }
      99             : 
     100          40 :     if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
     101             :         unsigned long int srounds;
     102             :         const char *num;
     103             :         char *endp;
     104             : 
     105           0 :         num = salt + ROUNDS_SIZE;
     106           0 :         srounds = strtoul(num, &endp, 10);
     107           0 :         if (*endp == '$') {
     108           0 :             salt = endp + 1;
     109           0 :             if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
     110           0 :             if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
     111           0 :             rounds = srounds;
     112           0 :             rounds_custom = true;
     113             :         }
     114             :     }
     115             : 
     116          40 :     salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
     117          40 :     key_len = strlen(key);
     118             : 
     119          40 :     if ((PTR_2_INT(key) % ALIGN64) != 0) {
     120          19 :         tmp = (char *)alloca(key_len + ALIGN64);
     121          19 :         key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
     122             :     }
     123             : 
     124          40 :     if (PTR_2_INT(salt) % ALIGN64 != 0) {
     125          21 :         tmp = (char *)alloca(salt_len + ALIGN64);
     126          21 :         salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
     127             :     }
     128             : 
     129          40 :     ret = nspr_nss_init();
     130          40 :     if (ret != EOK) {
     131           0 :         ret = EIO;
     132           0 :         goto done;
     133             :     }
     134             : 
     135          40 :     ctx = HASH_Create(HASH_AlgSHA512);
     136          40 :     if (!ctx) {
     137           0 :         ret = EIO;
     138           0 :         goto done;
     139             :     }
     140             : 
     141          40 :     alt_ctx = HASH_Create(HASH_AlgSHA512);
     142          40 :     if (!alt_ctx) {
     143           0 :         ret = EIO;
     144           0 :         goto done;
     145             :     }
     146             : 
     147             :     /* Prepare for the real work.  */
     148          40 :     HASH_Begin(ctx);
     149             : 
     150             :     /* Add the key string.  */
     151          40 :     HASH_Update(ctx, (const unsigned char *)key, key_len);
     152             : 
     153             :     /* The last part is the salt string. This must be at most 16
     154             :      * characters and it ends at the first `$' character (for
     155             :      * compatibility with existing implementations). */
     156          40 :     HASH_Update(ctx, (const unsigned char *)salt, salt_len);
     157             : 
     158             : 
     159             :     /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
     160             :      * The final result will be added to the first context. */
     161          40 :     HASH_Begin(alt_ctx);
     162             : 
     163             :     /* Add key. */
     164          40 :     HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
     165             : 
     166             :     /* Add salt. */
     167          40 :     HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
     168             : 
     169             :     /* Add key again. */
     170          40 :     HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
     171             : 
     172             :     /* Now get result of this (64 bytes) and add it to the other context. */
     173          40 :     HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx));
     174             : 
     175             :     /* Add for any character in the key one byte of the alternate sum. */
     176          40 :     for (cnt = key_len; cnt > 64; cnt -= 64) {
     177           0 :         HASH_Update(ctx, alt_result, 64);
     178             :     }
     179          40 :     HASH_Update(ctx, alt_result, cnt);
     180             : 
     181             :     /* Take the binary representation of the length of the key and for every
     182             :      * 1 add the alternate sum, for every 0 the key. */
     183         174 :     for (cnt = key_len; cnt > 0; cnt >>= 1) {
     184         134 :         if ((cnt & 1) != 0) {
     185          78 :             HASH_Update(ctx, alt_result, 64);
     186             :         } else {
     187          56 :             HASH_Update(ctx, (const unsigned char *)key, key_len);
     188             :         }
     189             :     }
     190             : 
     191             :     /* Create intermediate result. */
     192          40 :     HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
     193             : 
     194             :     /* Start computation of P byte sequence. */
     195          40 :     HASH_Begin(alt_ctx);
     196             : 
     197             :     /* For every character in the password add the entire password. */
     198         319 :     for (cnt = 0; cnt < key_len; cnt++) {
     199         279 :         HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
     200             :     }
     201             : 
     202             :     /* Finish the digest. */
     203          40 :     HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
     204             : 
     205             :     /* Create byte sequence P. */
     206          40 :     cp = p_bytes = alloca(key_len);
     207          40 :     for (cnt = key_len; cnt >= 64; cnt -= 64) {
     208           0 :         cp = mempcpy(cp, temp_result, 64);
     209             :     }
     210          40 :     memcpy(cp, temp_result, cnt);
     211             : 
     212             :     /* Start computation of S byte sequence. */
     213          40 :     HASH_Begin(alt_ctx);
     214             : 
     215             :     /* For every character in the password add the entire salt. */
     216        5120 :     for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
     217        5080 :         HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
     218             :     }
     219             : 
     220             :     /* Finish the digest. */
     221          40 :     HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
     222             : 
     223             :     /* Create byte sequence S.  */
     224          40 :     cp = s_bytes = alloca(salt_len);
     225          40 :     for (cnt = salt_len; cnt >= 64; cnt -= 64) {
     226           0 :         cp = mempcpy(cp, temp_result, 64);
     227             :     }
     228          40 :     memcpy(cp, temp_result, cnt);
     229             : 
     230             :     /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
     231      200040 :     for (cnt = 0; cnt < rounds; cnt++) {
     232             : 
     233      200000 :         HASH_Begin(ctx);
     234             : 
     235             :         /* Add key or last result. */
     236      200000 :         if ((cnt & 1) != 0) {
     237      100000 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     238             :         } else {
     239      100000 :             HASH_Update(ctx, alt_result, 64);
     240             :         }
     241             : 
     242             :         /* Add salt for numbers not divisible by 3. */
     243      200000 :         if (cnt % 3 != 0) {
     244      133320 :             HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len);
     245             :         }
     246             : 
     247             :         /* Add key for numbers not divisible by 7. */
     248      200000 :         if (cnt % 7 != 0) {
     249      171400 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     250             :         }
     251             : 
     252             :         /* Add key or last result. */
     253      200000 :         if ((cnt & 1) != 0) {
     254      100000 :             HASH_Update(ctx, alt_result, 64);
     255             :         } else {
     256      100000 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     257             :         }
     258             : 
     259             :         /* Create intermediate result. */
     260      200000 :         HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
     261             :     }
     262             : 
     263             :     /* Now we can construct the result string.
     264             :      * It consists of three parts. */
     265          40 :     if (buflen <= SALT_PREF_SIZE) {
     266           0 :         ret = ERANGE;
     267           0 :         goto done;
     268             :     }
     269             : 
     270          40 :     cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
     271          40 :     buflen -= SALT_PREF_SIZE;
     272             : 
     273          40 :     if (rounds_custom) {
     274           0 :         n = snprintf(cp, buflen, "%s%zu$",
     275             :                      sha512_rounds_prefix, rounds);
     276           0 :         if (n < 0 || n >= buflen) {
     277           0 :             ret = ERANGE;
     278           0 :             goto done;
     279             :         }
     280           0 :         cp += n;
     281           0 :         buflen -= n;
     282             :     }
     283             : 
     284          40 :     if (buflen <= salt_len + 1) {
     285           0 :         ret = ERANGE;
     286           0 :         goto done;
     287             :     }
     288          40 :     cp = stpncpy(cp, salt, salt_len);
     289          40 :     *cp++ = '$';
     290          40 :     buflen -= salt_len + 1;
     291             : 
     292             :     /* fuzzyfill the base 64 string */
     293          40 :     p1 = 0;
     294          40 :     p2 = 21;
     295          40 :     p3 = 42;
     296         880 :     for (n = 0; n < 21; n++) {
     297         840 :         b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
     298         840 :         if (buflen == 0) {
     299           0 :             ret = ERANGE;
     300           0 :             goto done;
     301             :         }
     302         840 :         pt = p1;
     303         840 :         p1 = p2 + 1;
     304         840 :         p2 = p3 + 1;
     305         840 :         p3 = pt + 1;
     306             :     }
     307             :     /* 64th and last byte */
     308          40 :     b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
     309          40 :     if (buflen == 0) {
     310           0 :         ret = ERANGE;
     311           0 :         goto done;
     312             :     }
     313             : 
     314          40 :     *cp = '\0';
     315          40 :     ret = EOK;
     316             : 
     317             : done:
     318             :     /* Clear the buffer for the intermediate result so that people attaching
     319             :      * to processes or reading core dumps cannot get any information. We do it
     320             :      * in this way to clear correct_words[] inside the SHA512 implementation
     321             :      * as well.  */
     322          40 :     if (ctx) HASH_Destroy(ctx);
     323          40 :     if (alt_ctx) HASH_Destroy(alt_ctx);
     324          40 :     if (p_bytes) memset(p_bytes, '\0', key_len);
     325          40 :     if (s_bytes) memset(s_bytes, '\0', salt_len);
     326          40 :     if (copied_key) memset(copied_key, '\0', key_len);
     327          40 :     if (copied_salt) memset(copied_salt, '\0', salt_len);
     328          40 :     memset(temp_result, '\0', sizeof(temp_result));
     329             : 
     330          40 :     return ret;
     331             : }
     332             : 
     333          40 : int s3crypt_sha512(TALLOC_CTX *memctx,
     334             :                    const char *key, const char *salt, char **_hash)
     335             : {
     336             :     char *hash;
     337          40 :     int hlen = (sizeof (sha512_salt_prefix) - 1
     338             :                 + sizeof (sha512_rounds_prefix) + 9 + 1
     339          40 :                 + strlen (salt) + 1 + 86 + 1);
     340             :     int ret;
     341             : 
     342          40 :     hash = talloc_size(memctx, hlen);
     343          40 :     if (!hash) return ENOMEM;
     344             : 
     345          40 :     ret = sha512_crypt_r(key, salt, hash, hlen);
     346          40 :     if (ret) return ret;
     347             : 
     348          40 :     *_hash = hash;
     349          40 :     return ret;
     350             : }
     351             : 
     352             : #define SALT_RAND_LEN 12
     353             : 
     354          19 : int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt)
     355             : {
     356             :     uint8_t rb[SALT_RAND_LEN];
     357             :     char *salt, *cp;
     358             :     size_t slen;
     359             :     int ret;
     360             : 
     361          19 :     ret = nspr_nss_init();
     362          19 :     if (ret != EOK) {
     363           0 :         return EIO;
     364             :     }
     365             : 
     366          19 :     salt = talloc_size(memctx, SALT_LEN_MAX + 1);
     367          19 :     if (!salt) {
     368           0 :         return ENOMEM;
     369             :     }
     370             : 
     371          19 :     ret = PK11_GenerateRandom(rb, SALT_RAND_LEN);
     372          19 :     if (ret != SECSuccess) {
     373           0 :         return EIO;
     374             :     }
     375             : 
     376          19 :     slen = SALT_LEN_MAX;
     377          19 :     cp = salt;
     378          19 :     b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
     379          19 :     b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
     380          19 :     b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]);
     381          19 :     b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]);
     382          19 :     *cp = '\0';
     383             : 
     384          19 :     *_salt = salt;
     385             : 
     386          19 :     return EOK;
     387             : }

Generated by: LCOV version 1.10