(root)/
libxcrypt-4.4.36/
lib/
crypt-scrypt.c
       1  /* Copyright (C) 2013 Alexander Peslyak
       2   * Copyright (C) 2018 Björn Esser <besser82@fedoraproject.org>
       3   *
       4   * Redistribution and use in source and binary forms, with or without
       5   * modification, are permitted.
       6   *
       7   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
       8   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       9   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      10   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      11   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      12   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      13   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      14   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      15   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      16   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      17   * SUCH DAMAGE.
      18   */
      19  
      20  #include "crypt-port.h"
      21  #include "crypt-hashes.h"
      22  
      23  #include <errno.h>
      24  
      25  #if INCLUDE_scrypt
      26  
      27  static int
      28  check_salt_char (char ch)
      29  {
      30    if (ch > 'z')
      31      return 0;
      32    if (ch >= 'a')
      33      return 1;
      34    if (ch > 'Z')
      35      return 0;
      36    if (ch >= 'A')
      37      return 1;
      38    if (ch > '9')
      39      return 0;
      40    if (ch >= '.' || ch == '$')
      41      return 1;
      42    return 0;
      43  }
      44  
      45  static int
      46  verify_salt (const char *setting, size_t set_size)
      47  {
      48    for (size_t i = 3 + 1 + 5 * 2; i < set_size; i++)
      49      {
      50        if (!check_salt_char (setting[i]))
      51          {
      52            /* Salt is terminated properly.
      53               Following characters don't matter.  */
      54            if (setting[i - 1] == '$')
      55              break;
      56  
      57            /* Salt has an invalid character.  */
      58            return 0;
      59          }
      60      }
      61    return 1;
      62  }
      63  
      64  static uint8_t *
      65  encode64_uint32 (uint8_t * dst, ssize_t dstlen,
      66                   uint32_t src, uint32_t srcbits)
      67  {
      68    uint32_t bit;
      69  
      70    for (bit = 0; bit < srcbits; bit += 6)
      71      {
      72        if (dstlen < 1)
      73          {
      74            errno = ERANGE;
      75            return NULL;
      76          }
      77        *dst++ = ascii64[src & 0x3f];
      78        dstlen--;
      79        src >>= 6;
      80      }
      81  
      82    *dst = '\0';
      83    return dst;
      84  }
      85  
      86  static uint8_t *
      87  encode64 (uint8_t * dst, ssize_t dstlen,
      88            const uint8_t * src, size_t srclen)
      89  {
      90    size_t i;
      91  
      92    for (i = 0; i < srclen; )
      93      {
      94        uint8_t * dnext;
      95        uint32_t value = 0, bits = 0;
      96        do
      97          {
      98            value |= (uint32_t) src[i++] << bits;
      99            bits += 8;
     100          }
     101        while (bits < 24 && i < srclen);
     102        dnext = encode64_uint32 (dst, dstlen, value, bits);
     103        if (!dnext)
     104          {
     105            errno = ERANGE;
     106            return NULL;
     107          }
     108        dstlen -= (dnext - dst);
     109        dst = dnext;
     110      }
     111  
     112    *dst = '\0';
     113    return dst;
     114  }
     115  
     116  static uint32_t
     117  N2log2 (uint64_t N)
     118  {
     119    uint32_t N_log2;
     120  
     121    if (N < 2)
     122      return 0;
     123  
     124    N_log2 = 2;
     125    while (N >> N_log2 != 0)
     126      N_log2++;
     127    N_log2--;
     128  
     129    if (N >> N_log2 != 1)
     130      return 0;
     131  
     132    return N_log2;
     133  }
     134  
     135  /*
     136   * Wrapper for crypt_yescrypt_rn to compute the hash.
     137   */
     138  void
     139  crypt_scrypt_rn (const char *phrase, size_t phr_size,
     140                   const char *setting, size_t set_size,
     141                   uint8_t *output, size_t o_size,
     142                   void *scratch, size_t s_size)
     143  {
     144    if (o_size < set_size + 1 + 43 + 1 ||
     145        CRYPT_OUTPUT_SIZE < set_size + 1 + 43 + 1)
     146      {
     147        errno = ERANGE;
     148        return;
     149      }
     150  
     151    /* Setting is invalid.  */
     152    if (strncmp (setting, "$7$", 3) || !verify_salt (setting, set_size))
     153      {
     154        errno = EINVAL;
     155        return;
     156      }
     157  
     158    crypt_yescrypt_rn (phrase, phr_size, setting, set_size,
     159                       output, o_size, scratch, s_size);
     160    return;
     161  }
     162  
     163  void
     164  gensalt_scrypt_rn (unsigned long count,
     165                     const uint8_t *rbytes, size_t nrbytes,
     166                     uint8_t *output, size_t o_size)
     167  {
     168    /* Up to 512 bits (64 bytes) of entropy for computing the salt portion
     169       of the MCF-setting are supported.  */
     170    nrbytes = (nrbytes > 64 ? 64 : nrbytes);
     171  
     172    if (o_size < 3 + 1 + 5 * 2 + BASE64_LEN (nrbytes) + 1 ||
     173        CRYPT_GENSALT_OUTPUT_SIZE < 3 + 1 + 5 * 2 + BASE64_LEN (nrbytes) + 1)
     174      {
     175        errno = ERANGE;
     176        return;
     177      }
     178  
     179    if ((count > 0 && count < 6) || count > 11 || nrbytes < 16)
     180      {
     181        errno = EINVAL;
     182        return;
     183      }
     184  
     185    /* Temporary buffer for operation.  The buffer is guaranteed to be
     186       large enough to hold the maximum size of the generated salt.  */
     187    uint8_t outbuf[CRYPT_GENSALT_OUTPUT_SIZE];
     188    uint8_t *out_p = outbuf + 4;
     189    ssize_t out_s = CRYPT_GENSALT_OUTPUT_SIZE - (out_p - outbuf);
     190  
     191    /* Valid cost parameters are from 6 to 11.  The default is 7.
     192       Any cost parameter below 6 is not to be considered strong
     193       enough anymore, because using less than 32 MiBytes of RAM
     194       when computing a hash is even weaker than bcrypt ($2y$).
     195       These are used to set scrypt's 'N' and 'r' parameters as
     196       follows:
     197       N (block count) is specified in units of r (block size,
     198       adjustable in steps of 128 bytes).
     199  
     200       128 bytes * r = size of each memory block
     201  
     202       128 bytes * r * N = total amount of memory used for hashing
     203                           in N blocks of r * 128 bytes.
     204  
     205       The author of yescrypt recommends in the documentation to use
     206       r=8 (a block size of 1 KiB) for total sizes of 2 MiB and less,
     207       and r=32 (a block size of 4KiB) above that.
     208       This has to do with the typical per-core last-level cache sizes
     209       of current CPUs.  */
     210    if (count == 0)
     211      count = 7;
     212  
     213    uint32_t p = 1;
     214    uint32_t r = 32;
     215    uint64_t N = 1ULL << (count + 7); // 6 -> 8192, 7 -> 16384, ... 11 -> 262144
     216  
     217    if (out_s > (ssize_t) BASE64_LEN (30))
     218      {
     219        outbuf[0] = '$';
     220        outbuf[1] = '7';
     221        outbuf[2] = '$';
     222        outbuf[3] = ascii64[N2log2 (N)];
     223  
     224        out_p = encode64_uint32 (out_p, out_s, r, 30);
     225        out_s -= (out_p - outbuf);
     226      }
     227  
     228    if (out_p && out_s > (ssize_t) BASE64_LEN (30))
     229      {
     230        out_p = encode64_uint32 (out_p, out_s, p, 30);
     231        out_s -= (out_p - outbuf);
     232      }
     233  
     234    if (out_p && out_s > (ssize_t) BASE64_LEN (nrbytes))
     235      {
     236        out_p = encode64 (out_p, out_s, rbytes, nrbytes);
     237      }
     238  
     239    if (out_p)
     240      {
     241        strcpy_or_abort (output, o_size, outbuf);
     242      }
     243  
     244    return;
     245  }
     246  
     247  #endif /* INCLUDE_scrypt */