Blame crypt-gensalt.c

Packit 13e0ca
/*
Packit 13e0ca
 * Written by Solar Designer and placed in the public domain.
Packit 13e0ca
 * See crypt-bcrypt.c for more information.
Packit 13e0ca
 *
Packit 13e0ca
 * This file contains setting-string generation code shared among the
Packit 13e0ca
 * MD5, SHA256, and SHA512 hash algorithms, which use very similar
Packit 13e0ca
 * setting formats.  Setting-string generation for bcrypt and DES is
Packit 13e0ca
 * entirely in crypt-bcrypt.c and crypt-des.c respectively.
Packit 13e0ca
 */
Packit 13e0ca
Packit 13e0ca
#include "crypt-port.h"
Packit 13e0ca
#include "crypt-private.h"
Packit 13e0ca
Packit 13e0ca
#include <errno.h>
Packit 13e0ca
#include <stdio.h>
Packit 13e0ca
Packit 13e0ca
#if INCLUDE_md5 || INCLUDE_sha256 || INCLUDE_sha512
Packit 13e0ca
Packit 13e0ca
static const unsigned char _xcrypt_itoa64[64 + 1] =
Packit 13e0ca
  "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
Packit 13e0ca
Packit 13e0ca
void
Packit 13e0ca
gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount,
Packit 13e0ca
                unsigned long mincount, unsigned long maxcount,
Packit 13e0ca
                unsigned long count,
Packit 13e0ca
                const uint8_t *rbytes, size_t nrbytes,
Packit 13e0ca
                uint8_t *output, size_t output_size)
Packit 13e0ca
{
Packit 13e0ca
  if (count == 0)
Packit 13e0ca
    count = defcount;
Packit 13e0ca
  if (count < mincount || count > maxcount)
Packit 13e0ca
    {
Packit 13e0ca
      errno = EINVAL;
Packit 13e0ca
      return;
Packit 13e0ca
    }
Packit 13e0ca
Packit 13e0ca
  /* We will use more rbytes if available, but at least this much is
Packit 13e0ca
     required.  */
Packit 13e0ca
  if (nrbytes < 3)
Packit 13e0ca
    {
Packit 13e0ca
      errno = EINVAL;
Packit 13e0ca
      return;
Packit 13e0ca
    }
Packit 13e0ca
Packit 13e0ca
  /* Compute how much space we need.  */
Packit 13e0ca
  size_t output_len = 8; /* $x$ssss\0 */
Packit 13e0ca
  if (count != defcount)
Packit 13e0ca
    {
Packit 13e0ca
      output_len += 9; /* rounds=1$ */
Packit 13e0ca
      for (unsigned long ceiling = 10; ceiling < count; ceiling *= 10)
Packit 13e0ca
        output_len += 1;
Packit 13e0ca
    }
Packit 13e0ca
  if (output_size < output_len)
Packit 13e0ca
    {
Packit 13e0ca
      errno = ERANGE;
Packit 13e0ca
      return;
Packit 13e0ca
    }
Packit 13e0ca
Packit 13e0ca
  size_t written;
Packit 13e0ca
  if (count == defcount)
Packit 13e0ca
    {
Packit 13e0ca
      output[0] = '$';
Packit 13e0ca
      output[1] = (unsigned char)tag;
Packit 13e0ca
      output[2] = '$';
Packit 13e0ca
      written = 3;
Packit 13e0ca
    }
Packit 13e0ca
  else
Packit 13e0ca
    written = (size_t) snprintf ((char *)output, output_size,
Packit 13e0ca
                                 "$%c$rounds=%lu$", tag, count);
Packit 13e0ca
Packit 13e0ca
  /* The length calculation above should ensure that this is always true.  */
Packit 13e0ca
  assert (written + 5 < output_size);
Packit 13e0ca
Packit 13e0ca
  size_t used_rbytes = 0;
Packit 13e0ca
  while (written + 5 < output_size &&
Packit 13e0ca
         used_rbytes + 3 < nrbytes &&
Packit 13e0ca
         (used_rbytes * 4 / 3) < maxsalt)
Packit 13e0ca
    {
Packit 13e0ca
      unsigned long value =
Packit 13e0ca
        ((unsigned long) (unsigned char) rbytes[used_rbytes + 0] <<  0) |
Packit 13e0ca
        ((unsigned long) (unsigned char) rbytes[used_rbytes + 1] <<  8) |
Packit 13e0ca
        ((unsigned long) (unsigned char) rbytes[used_rbytes + 2] << 16);
Packit 13e0ca
Packit 13e0ca
      output[written + 0] = _xcrypt_itoa64[value & 0x3f];
Packit 13e0ca
      output[written + 1] = _xcrypt_itoa64[(value >> 6) & 0x3f];
Packit 13e0ca
      output[written + 2] = _xcrypt_itoa64[(value >> 12) & 0x3f];
Packit 13e0ca
      output[written + 3] = _xcrypt_itoa64[(value >> 18) & 0x3f];
Packit 13e0ca
Packit 13e0ca
      written += 4;
Packit 13e0ca
      used_rbytes += 3;
Packit 13e0ca
    }
Packit 13e0ca
Packit 13e0ca
  output[written] = '\0';
Packit 13e0ca
}
Packit 13e0ca
Packit 13e0ca
#endif