LCOV - code coverage report
Current view: top level - util/crypto/nss - nss_sha512crypt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 146 88.4 %
Date: 2012-11-29 Functions: 4 4 100.0 %
Branches: 53 90 58.9 %

           Branch data     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 <endian.h>
      14                 :            : #include <errno.h>
      15                 :            : #include <limits.h>
      16                 :            : #include <stdbool.h>
      17                 :            : #include <stdint.h>
      18                 :            : #include <stdio.h>
      19                 :            : #include <stdlib.h>
      20                 :            : #include <string.h>
      21                 :            : #include <sys/param.h>
      22                 :            : #include <sys/types.h>
      23                 :            : 
      24                 :            : #include "util/util.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                 :        114 : 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         [ -  + ]:        114 :     if (*len < n) n = *len;
      57                 :            : 
      58                 :        114 :     w = (b2 << 16) | (b1 << 8) | b0;
      59         [ +  + ]:        560 :     for (i = 0; i < n; i++) {
      60                 :        446 :         (*dest)[i] = b64t[w & 0x3f];
      61                 :        446 :         w >>= 6;
      62                 :            :     }
      63                 :            : 
      64                 :        114 :     *len -= i;
      65                 :        114 :     *dest += i;
      66                 :        114 : }
      67                 :            : 
      68                 :            : #define PTR_2_INT(x) ((x) - ((__typeof__ (x)) NULL))
      69                 :            : #define ALIGN64 __alignof__(uint64_t)
      70                 :            : 
      71                 :          5 : 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                 :          5 :     size_t rounds = ROUNDS_DEFAULT;
      78                 :          5 :     bool rounds_custom = false;
      79                 :          5 :     HASHContext *alt_ctx = NULL;
      80                 :          5 :     HASHContext *ctx = NULL;
      81                 :            :     size_t salt_len;
      82                 :            :     size_t key_len;
      83                 :            :     size_t cnt;
      84                 :          5 :     char *copied_salt = NULL;
      85                 :          5 :     char *copied_key = NULL;
      86                 :          5 :     char *p_bytes = NULL;
      87                 :          5 :     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         [ +  + ]:          5 :     if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
      96                 :            :         /* Skip salt prefix.  */
      97                 :          4 :         salt += SALT_PREF_SIZE;
      98                 :            :     }
      99                 :            : 
     100         [ -  + ]:          5 :     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 [ -  + ][ #  # ]:          5 :     salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
     117                 :          5 :     key_len = strlen(key);
     118                 :            : 
     119         [ -  + ]:          5 :     if ((PTR_2_INT(key) % ALIGN64) != 0) {
     120                 :          0 :         tmp = (char *)alloca(key_len + ALIGN64);
     121                 :          0 :         key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
     122                 :            :     }
     123                 :            : 
     124         [ +  + ]:          5 :     if (PTR_2_INT(salt) % ALIGN64 != 0) {
     125                 :          4 :         tmp = (char *)alloca(salt_len + ALIGN64);
     126                 :          4 :         salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
     127                 :            :     }
     128                 :            : 
     129                 :          5 :     ret = nspr_nss_init();
     130         [ +  - ]:          5 :     if (ret != EOK) {
     131                 :            :         ret = EIO;
     132                 :            :         goto done;
     133                 :            :     }
     134                 :            : 
     135                 :          5 :     ctx = HASH_Create(HASH_AlgSHA512);
     136         [ +  - ]:          5 :     if (!ctx) {
     137                 :            :         ret = EIO;
     138                 :            :         goto done;
     139                 :            :     }
     140                 :            : 
     141                 :          5 :     alt_ctx = HASH_Create(HASH_AlgSHA512);
     142         [ +  - ]:          5 :     if (!alt_ctx) {
     143                 :            :         ret = EIO;
     144                 :            :         goto done;
     145                 :            :     }
     146                 :            : 
     147                 :            :     /* Prepare for the real work.  */
     148                 :          5 :     HASH_Begin(ctx);
     149                 :            : 
     150                 :            :     /* Add the key string.  */
     151                 :          5 :     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                 :          5 :     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                 :          5 :     HASH_Begin(alt_ctx);
     162                 :            : 
     163                 :            :     /* Add key. */
     164                 :          5 :     HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
     165                 :            : 
     166                 :            :     /* Add salt. */
     167                 :          5 :     HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
     168                 :            : 
     169                 :            :     /* Add key again. */
     170                 :          5 :     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                 :          5 :     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         [ -  + ]:          5 :     for (cnt = key_len; cnt > 64; cnt -= 64) {
     177                 :          0 :         HASH_Update(ctx, alt_result, 64);
     178                 :            :     }
     179                 :          5 :     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         [ +  + ]:         21 :     for (cnt = key_len; cnt > 0; cnt >>= 1) {
     184         [ +  + ]:         16 :         if ((cnt & 1) != 0) {
     185                 :         13 :             HASH_Update(ctx, alt_result, 64);
     186                 :            :         } else {
     187                 :          3 :             HASH_Update(ctx, (const unsigned char *)key, key_len);
     188                 :            :         }
     189                 :            :     }
     190                 :            : 
     191                 :            :     /* Create intermediate result. */
     192                 :          5 :     HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
     193                 :            : 
     194                 :            :     /* Start computation of P byte sequence. */
     195                 :          5 :     HASH_Begin(alt_ctx);
     196                 :            : 
     197                 :            :     /* For every character in the password add the entire password. */
     198         [ +  + ]:         50 :     for (cnt = 0; cnt < key_len; cnt++) {
     199                 :         45 :         HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
     200                 :            :     }
     201                 :            : 
     202                 :            :     /* Finish the digest. */
     203                 :          5 :     HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
     204                 :            : 
     205                 :            :     /* Create byte sequence P. */
     206                 :          5 :     cp = p_bytes = alloca(key_len);
     207         [ -  + ]:          5 :     for (cnt = key_len; cnt >= 64; cnt -= 64) {
     208                 :          0 :         cp = mempcpy(cp, temp_result, 64);
     209                 :            :     }
     210                 :          5 :     memcpy(cp, temp_result, cnt);
     211                 :            : 
     212                 :            :     /* Start computation of S byte sequence. */
     213                 :          5 :     HASH_Begin(alt_ctx);
     214                 :            : 
     215                 :            :     /* For every character in the password add the entire salt. */
     216         [ +  + ]:        259 :     for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
     217                 :        254 :         HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
     218                 :            :     }
     219                 :            : 
     220                 :            :     /* Finish the digest. */
     221                 :          5 :     HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));
     222                 :            : 
     223                 :            :     /* Create byte sequence S.  */
     224                 :          5 :     cp = s_bytes = alloca(salt_len);
     225         [ -  + ]:          5 :     for (cnt = salt_len; cnt >= 64; cnt -= 64) {
     226                 :          0 :         cp = mempcpy(cp, temp_result, 64);
     227                 :            :     }
     228                 :          5 :     memcpy(cp, temp_result, cnt);
     229                 :            : 
     230                 :            :     /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
     231         [ +  + ]:      25005 :     for (cnt = 0; cnt < rounds; cnt++) {
     232                 :            : 
     233                 :      25000 :         HASH_Begin(ctx);
     234                 :            : 
     235                 :            :         /* Add key or last result. */
     236         [ +  + ]:      25000 :         if ((cnt & 1) != 0) {
     237                 :      12500 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     238                 :            :         } else {
     239                 :      12500 :             HASH_Update(ctx, alt_result, 64);
     240                 :            :         }
     241                 :            : 
     242                 :            :         /* Add salt for numbers not divisible by 3. */
     243         [ +  + ]:      25000 :         if (cnt % 3 != 0) {
     244                 :      16665 :             HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len);
     245                 :            :         }
     246                 :            : 
     247                 :            :         /* Add key for numbers not divisible by 7. */
     248         [ +  + ]:      25000 :         if (cnt % 7 != 0) {
     249                 :      21425 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     250                 :            :         }
     251                 :            : 
     252                 :            :         /* Add key or last result. */
     253         [ +  + ]:      25000 :         if ((cnt & 1) != 0) {
     254                 :      12500 :             HASH_Update(ctx, alt_result, 64);
     255                 :            :         } else {
     256                 :      12500 :             HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
     257                 :            :         }
     258                 :            : 
     259                 :            :         /* Create intermediate result. */
     260                 :      25000 :         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         [ +  - ]:          5 :     if (buflen <= SALT_PREF_SIZE) {
     266                 :            :         ret = ERANGE;
     267                 :            :         goto done;
     268                 :            :     }
     269                 :            : 
     270                 :          5 :     cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
     271                 :          5 :     buflen -= SALT_PREF_SIZE;
     272                 :            : 
     273         [ -  + ]:          5 :     if (rounds_custom) {
     274                 :          0 :         n = snprintf(cp, buflen, "%s%zu$",
     275                 :            :                      sha512_rounds_prefix, rounds);
     276 [ #  # ][ #  # ]:          0 :         if (n < 0 || n >= buflen) {
     277                 :            :             ret = ERANGE;
     278                 :            :             goto done;
     279                 :            :         }
     280                 :          0 :         cp += n;
     281                 :          0 :         buflen -= n;
     282                 :            :     }
     283                 :            : 
     284         [ +  - ]:          5 :     if (buflen <= salt_len + 1) {
     285                 :            :         ret = ERANGE;
     286                 :            :         goto done;
     287                 :            :     }
     288                 :          5 :     cp = __stpncpy(cp, salt, salt_len);
     289                 :          5 :     *cp++ = '$';
     290                 :          5 :     buflen -= salt_len + 1;
     291                 :            : 
     292                 :            :     /* fuzzyfill the base 64 string */
     293                 :          5 :     p1 = 0;
     294                 :          5 :     p2 = 21;
     295                 :          5 :     p3 = 42;
     296         [ +  + ]:        110 :     for (n = 0; n < 21; n++) {
     297                 :        105 :         b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
     298         [ +  - ]:        105 :         if (buflen == 0) {
     299                 :            :             ret = ERANGE;
     300                 :            :             goto done;
     301                 :            :         }
     302                 :        105 :         pt = p1;
     303                 :        105 :         p1 = p2 + 1;
     304                 :        105 :         p2 = p3 + 1;
     305                 :        105 :         p3 = pt + 1;
     306                 :            :     }
     307                 :            :     /* 64th and last byte */
     308                 :          5 :     b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
     309         [ +  - ]:          5 :     if (buflen == 0) {
     310                 :            :         ret = ERANGE;
     311                 :            :         goto done;
     312                 :            :     }
     313                 :            : 
     314                 :          5 :     *cp = '\0';
     315                 :          5 :     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         [ +  - ]:          5 :     if (ctx) HASH_Destroy(ctx);
     323         [ +  - ]:          5 :     if (alt_ctx) HASH_Destroy(alt_ctx);
     324         [ +  - ]:          5 :     if (p_bytes) memset(p_bytes, '\0', key_len);
     325         [ +  - ]:          5 :     if (s_bytes) memset(s_bytes, '\0', salt_len);
     326         [ -  + ]:          5 :     if (copied_key) memset(copied_key, '\0', key_len);
     327         [ +  + ]:          5 :     if (copied_salt) memset(copied_salt, '\0', salt_len);
     328                 :          5 :     memset(temp_result, '\0', sizeof(temp_result));
     329                 :            : 
     330                 :          5 :     return ret;
     331                 :            : }
     332                 :            : 
     333                 :          5 : int s3crypt_sha512(TALLOC_CTX *memctx,
     334                 :            :                    const char *key, const char *salt, char **_hash)
     335                 :            : {
     336                 :            :     char *hash;
     337                 :          5 :     int hlen = (sizeof (sha512_salt_prefix) - 1
     338                 :            :                 + sizeof (sha512_rounds_prefix) + 9 + 1
     339                 :          5 :                 + strlen (salt) + 1 + 86 + 1);
     340                 :            :     int ret;
     341                 :            : 
     342                 :          5 :     hash = talloc_size(memctx, hlen);
     343         [ +  - ]:          5 :     if (!hash) return ENOMEM;
     344                 :            : 
     345                 :          5 :     ret = sha512_crypt_r(key, salt, hash, hlen);
     346         [ +  - ]:          5 :     if (ret) return ret;
     347                 :            : 
     348                 :          5 :     *_hash = hash;
     349                 :          5 :     return ret;
     350                 :            : }
     351                 :            : 
     352                 :            : #define SALT_RAND_LEN 12
     353                 :            : 
     354                 :          1 : 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                 :          1 :     ret = nspr_nss_init();
     362         [ +  - ]:          1 :     if (ret != EOK) {
     363                 :            :         return EIO;
     364                 :            :     }
     365                 :            : 
     366                 :          1 :     salt = talloc_size(memctx, SALT_LEN_MAX + 1);
     367         [ +  - ]:          1 :     if (!salt) {
     368                 :            :         return ENOMEM;
     369                 :            :     }
     370                 :            : 
     371                 :          1 :     ret = PK11_GenerateRandom(rb, SALT_RAND_LEN);
     372         [ +  - ]:          1 :     if (ret != SECSuccess) {
     373                 :            :         return EIO;
     374                 :            :     }
     375                 :            : 
     376                 :          1 :     slen = SALT_LEN_MAX;
     377                 :          1 :     cp = salt;
     378                 :          1 :     b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
     379                 :          1 :     b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
     380                 :          1 :     b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]);
     381                 :          1 :     b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]);
     382                 :          1 :     *cp = '\0';
     383                 :            : 
     384                 :          1 :     *_salt = salt;
     385                 :            : 
     386                 :            :     return EOK;
     387                 :            : }

Generated by: LCOV version 1.9