(root)/
libxcrypt-4.4.36/
test/
gensalt-extradata.c
       1  /* Test that the prefix argument to crypt_gensalt affects only the
       2     choice of hashing method, not any of the parameters or the salt.
       3  
       4     Written by Zack Weinberg <zackw at panix.com> in 2018.
       5     To the extent possible under law, Zack Weinberg has waived all
       6     copyright and related or neighboring rights to this work.
       7  
       8     See https://creativecommons.org/publicdomain/zero/1.0/ for further
       9     details.  */
      10  
      11  #include "crypt-port.h"
      12  
      13  #include <errno.h>
      14  #include <stdio.h>
      15  
      16  /* Random bytes used when calling crypt_gensalt; for determinism, these
      17     are fixed from run to run.  */
      18  #define N_RBYTES 64ul
      19  
      20  static const char rbytes1[] =
      21    "90idUkI2+mu2E/tMTViD418j2sPdEYq9LYq0yRW7RYhr4RqQ+oVzIIEcfJBqpf/D";
      22  
      23  static const char rbytes2[] =
      24    "sEwXQxrjBTEADauxCpvOQqq7iU9oq6uJ+Iux/fbhtLRj1MWgBFyo/t+nh/nzm0Kn";
      25  
      26  static_assert(sizeof rbytes1 == N_RBYTES + 1, "rbytes1 is wrong length");
      27  static_assert(sizeof rbytes2 == N_RBYTES + 1, "rbytes2 is wrong length");
      28  
      29  struct testcase
      30  {
      31    const char *prefix;
      32    unsigned long count1;
      33    unsigned long count2;
      34  };
      35  
      36  /* This list should include one entry for each potentially-supported
      37     hash prefix.  If the hash method has tunable cost, set count1 and
      38     count2 to two different nonzero values, within the supported cost
      39     range.  Neither value should equal the default cost.  If the hash
      40     method does not have tunable cost, set count1 and count2 to zero.  */
      41  static const struct testcase testcases[] =
      42  {
      43  #if INCLUDE_descrypt || INCLUDE_bigcrypt
      44    { "", 0, 0 },
      45  #endif
      46  #if INCLUDE_bsdicrypt
      47    { "_", 7019, 1120211 },
      48  #endif
      49  #if INCLUDE_nt
      50    { "$3$", 0, 0 },
      51  #endif
      52  #if INCLUDE_md5crypt
      53    { "$1$", 0, 0 },
      54  #endif
      55  #if INCLUDE_sunmd5
      56    { "$md5",  7019, 1120211 },
      57  #endif
      58  #if INCLUDE_sha1crypt
      59    { "$sha1", 7019, 1120211 },
      60  #endif
      61  #if INCLUDE_sha256crypt
      62    { "$5$", 7019, 1120211 },
      63  #endif
      64  #if INCLUDE_sha512crypt
      65    { "$6$", 7019, 1120211 },
      66  #endif
      67  #if INCLUDE_bcrypt
      68    { "$2b$", 7, 11 },
      69  #endif
      70  #if INCLUDE_bcrypt_y
      71    { "$2y$", 7, 11 },
      72  #endif
      73  #if INCLUDE_bcrypt_a
      74    { "$2a$", 7, 11 },
      75  #endif
      76  #if INCLUDE_scrypt
      77    { "$7$", 7, 11, },
      78  #endif
      79  #if INCLUDE_yescrypt
      80    { "$y$", 7, 11, },
      81  #endif
      82  #if INCLUDE_gost_yescrypt
      83    { "$gy$", 7, 11, },
      84  #endif
      85    { 0, 0, 0, }
      86  };
      87  
      88  static int
      89  do_crypt_gensalt(const char *prefix,
      90                   const char rbytes[MIN_SIZE(N_RBYTES)],
      91                   unsigned long count,
      92                   char outbuf[MIN_SIZE(CRYPT_GENSALT_OUTPUT_SIZE)])
      93  {
      94    /* Detect failure to NUL-terminate the output properly.  */
      95    static int ncalls = 0;
      96    memset(outbuf, '!' + (ncalls % ('~' - '!' + 1)),
      97           CRYPT_GENSALT_OUTPUT_SIZE - 1);
      98    outbuf[CRYPT_GENSALT_OUTPUT_SIZE - 1] = 0;
      99    ncalls++;
     100  
     101    char *rv = crypt_gensalt_rn(prefix, count, rbytes, N_RBYTES,
     102                                outbuf, CRYPT_GENSALT_OUTPUT_SIZE);
     103    if (rv == 0)
     104      {
     105        printf("ERROR: gensalt(%s, %lu, %c%c..., %lu, outbuf, %lu) = 0/%s\n",
     106               prefix, count, rbytes[0], rbytes[1],
     107               N_RBYTES, (unsigned long)CRYPT_GENSALT_OUTPUT_SIZE,
     108               strerror(errno));
     109        outbuf[0] = '*';
     110        memset (outbuf+1, 0, CRYPT_GENSALT_OUTPUT_SIZE-1);
     111        return 1;
     112      }
     113    else if (rv[0] == '*')
     114      {
     115        printf("ERROR: gensalt(%s, %lu, %c%c..., %lu, outbuf, %lu) = %s/%s\n",
     116               prefix, count, rbytes[0], rbytes[1],
     117               N_RBYTES, (unsigned long)CRYPT_GENSALT_OUTPUT_SIZE,
     118               outbuf, strerror(errno));
     119        outbuf[0] = '*';
     120        memset (outbuf+1, 0, CRYPT_GENSALT_OUTPUT_SIZE-1);
     121        return 1;
     122      }
     123    else
     124      return 0;
     125  }
     126  
     127  static int
     128  do_check_equal(const char *stst, const char *sref,
     129                 const char *prefix, const char rbytes[N_RBYTES],
     130                 unsigned long count, const char *setting)
     131  {
     132    if (!strcmp(stst, sref))
     133      return 0;
     134  
     135    printf("FAIL: expected %s\n"
     136           "           got %s\n"
     137           "  from %s, %lu, %c%c...\n"
     138           "   and %s\n",
     139           sref, stst, prefix, count, rbytes[0], rbytes[1], setting);
     140    return 1;
     141  }
     142  
     143  int
     144  main(void)
     145  {
     146    int status = 0;
     147    char sref[6][CRYPT_GENSALT_OUTPUT_SIZE];
     148    char stst[CRYPT_GENSALT_OUTPUT_SIZE];
     149  
     150    for (size_t i = 0; testcases[i].prefix; i++)
     151      {
     152        const char *prefix   = testcases[i].prefix;
     153        unsigned long count1 = testcases[i].count1;
     154        unsigned long count2 = testcases[i].count2;
     155        int ncases;
     156  
     157        memset(sref, 0, sizeof sref);
     158  
     159        /* If count1 and count2 are both nonzero, then they should also
     160           be unequal, and we have six reference cases:
     161           (0, count1, count2) x (rbytes1, rbytes2).
     162           If count1 and count2 are both zero, then we only have two
     163           reference cases: 0 x (rbytes1, rbytes2) (this happens when the
     164           hash method doesn't have tunable cost).
     165           It is incorrect for only one of count1 and count2 to be zero,
     166           or for them to be equal but nonzero.  */
     167        if (count1 == 0 && count2 == 0)
     168          {
     169            ncases = 2;
     170            status |= do_crypt_gensalt(prefix, rbytes1, 0, sref[0]);
     171            status |= do_crypt_gensalt(prefix, rbytes2, 0, sref[1]);
     172          }
     173        else if (count1 != 0 && count2 != 0 && count1 != count2)
     174          {
     175            ncases = 6;
     176            status |= do_crypt_gensalt(prefix, rbytes1, 0,      sref[0]);
     177            status |= do_crypt_gensalt(prefix, rbytes2, 0,      sref[1]);
     178            status |= do_crypt_gensalt(prefix, rbytes1, count1, sref[2]);
     179            status |= do_crypt_gensalt(prefix, rbytes2, count1, sref[3]);
     180            status |= do_crypt_gensalt(prefix, rbytes1, count2, sref[4]);
     181            status |= do_crypt_gensalt(prefix, rbytes2, count2, sref[5]);
     182          }
     183        else
     184          {
     185            printf ("ERROR: %zu/%s: inappropriate count1=%lu count2=%lu\n",
     186                    i, prefix, count1, count2);
     187            status = 1;
     188            continue;
     189          }
     190  
     191        /* At this point, sref[0..ncases] are filled with setting
     192           strings corresponding to different combinations of salt and
     193           cost.  If we reuse those strings as prefixes for crypt_gensalt,
     194           none of the additional information should affect the output.  */
     195        for (int j = 0; j < ncases; j++)
     196          {
     197            if (sref[j][0] == '*')
     198              continue; /* initial crypt_gensalt call failed */
     199            if (count1 == 0 && count2 == 0)
     200              {
     201                status |= do_crypt_gensalt(sref[j], rbytes1, 0, stst);
     202                status |= do_check_equal(stst, sref[0],
     203                                         prefix, rbytes1, 0, sref[j]);
     204  
     205                status |= do_crypt_gensalt(sref[j], rbytes2, 0, stst);
     206                status |= do_check_equal(stst, sref[1],
     207                                         prefix, rbytes2, 0, sref[j]);
     208              }
     209            else
     210              {
     211                status |= do_crypt_gensalt(sref[j], rbytes1, 0,      stst);
     212                status |= do_check_equal(stst, sref[0],
     213                                         prefix, rbytes1, 0, sref[j]);
     214  
     215                status |= do_crypt_gensalt(sref[j], rbytes2, 0,      stst);
     216                status |= do_check_equal(stst, sref[1],
     217                                         prefix, rbytes2, 0, sref[j]);
     218  
     219                status |= do_crypt_gensalt(sref[j], rbytes1, count1, stst);
     220                status |= do_check_equal(stst, sref[2],
     221                                         prefix, rbytes1, count1, sref[j]);
     222  
     223                status |= do_crypt_gensalt(sref[j], rbytes2, count1, stst);
     224                status |= do_check_equal(stst, sref[3],
     225                                         prefix, rbytes2, count1, sref[j]);
     226  
     227                status |= do_crypt_gensalt(sref[j], rbytes1, count2, stst);
     228                status |= do_check_equal(stst, sref[4],
     229                                         prefix, rbytes1, count2, sref[j]);
     230  
     231                status |= do_crypt_gensalt(sref[j], rbytes2, count2, stst);
     232                status |= do_check_equal(stst, sref[5],
     233                                         prefix, rbytes2, count2, sref[j]);
     234              }
     235          }
     236  
     237      }
     238  
     239    return status;
     240  }