(root)/
libxcrypt-4.4.36/
lib/
util-gensalt-sha.c
       1  /*
       2   * Written by Solar Designer and placed in the public domain.
       3   * See crypt-bcrypt.c for more information.
       4   *
       5   * This file contains setting-string generation code shared among the
       6   * MD5, SHA256, and SHA512 hash algorithms, which use very similar
       7   * setting formats.  Setting-string generation for bcrypt and DES is
       8   * entirely in crypt-bcrypt.c and crypt-des.c respectively.
       9   */
      10  
      11  #include "crypt-port.h"
      12  
      13  #include <errno.h>
      14  #include <stdio.h>
      15  
      16  #if INCLUDE_md5crypt || INCLUDE_sha256crypt || INCLUDE_sha512crypt
      17  
      18  void
      19  gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount,
      20                  unsigned long mincount, unsigned long maxcount,
      21                  unsigned long count,
      22                  const uint8_t *rbytes, size_t nrbytes,
      23                  uint8_t *output, size_t output_size)
      24  {
      25    /* We will use more rbytes if available, but at least this much is
      26       required.  */
      27    if (nrbytes < 3)
      28      {
      29        errno = EINVAL;
      30        return;
      31      }
      32  
      33    if (count == 0)
      34      count = defcount;
      35    if (count < mincount)
      36      count = mincount;
      37    if (count > maxcount)
      38      count = maxcount;
      39  
      40    /* Compute how much space we need.  */
      41    size_t output_len = 8; /* $x$ssss\0 */
      42    if (count != defcount)
      43      {
      44        output_len += 9; /* rounds=1$ */
      45        for (unsigned long ceiling = 10; ceiling < count; ceiling *= 10)
      46          output_len += 1;
      47      }
      48    if (output_size < output_len)
      49      {
      50        errno = ERANGE;
      51        return;
      52      }
      53  
      54    size_t written;
      55    if (count == defcount)
      56      {
      57        output[0] = '$';
      58        output[1] = (unsigned char)tag;
      59        output[2] = '$';
      60        written = 3;
      61      }
      62    else
      63      written = (size_t) snprintf ((char *)output, output_size,
      64                                   "$%c$rounds=%lu$", tag, count);
      65  
      66    /* The length calculation above should ensure that this is always true.  */
      67    assert (written + 5 < output_size);
      68  
      69    size_t used_rbytes = 0;
      70    while (written + 5 < output_size &&
      71           used_rbytes + 3 < nrbytes &&
      72           (used_rbytes * 4 / 3) < maxsalt)
      73      {
      74        unsigned long value =
      75          ((unsigned long) (unsigned char) rbytes[used_rbytes + 0] <<  0) |
      76          ((unsigned long) (unsigned char) rbytes[used_rbytes + 1] <<  8) |
      77          ((unsigned long) (unsigned char) rbytes[used_rbytes + 2] << 16);
      78  
      79        output[written + 0] = ascii64[value & 0x3f];
      80        output[written + 1] = ascii64[(value >> 6) & 0x3f];
      81        output[written + 2] = ascii64[(value >> 12) & 0x3f];
      82        output[written + 3] = ascii64[(value >> 18) & 0x3f];
      83  
      84        written += 4;
      85        used_rbytes += 3;
      86      }
      87  
      88    output[written] = '\0';
      89  }
      90  
      91  #endif