#include "crypt-port.h"
#include "crypt-base.h"

#include <stdio.h>
#include <stdlib.h>

#if INCLUDE_sunmd5

const char *password   = "abcdefg";
const char *tests[][3] =
{
  /* Hashes have been computed with the following program:

     #!/usr/bin/python

     from passlib.hash import sun_md5_crypt
     import csv

     with open('sunmd5.txt') as csvfile:
         params = csv.reader(csvfile)
         for row in params:
             print(sun_md5_crypt.using(rounds=int(row[0]),
                                       salt=row[1]).hash("abcdefg"))

     The used csv file had the following format:

     <rounds>,<salt(8byte)> (when no rounds parameter was given,
                             rounds were set to zero.)

     The salts have been generated by crypt_gensalt on OpenSolaris.


     Test X.0: checks the password is encryptable with the full hash
               as setting.
     Test X.1: checks the password is encryptable with the initially
               used salt as setting.
     Test X.0: checks for the bug in Sun's original implementation
               is present.
               See:  http://passlib.readthedocs.io/en/stable/lib/passlib.hash.sun_md5_crypt.html#smc-bare-salt
   */
  {
    "$md5,rounds=5619$9ZLwtuT0$$mLoRQuWY/qcxCRWhD1C2M.",
    "$md5,rounds=5619$9ZLwtuT0$",
    "$md5,rounds=5619$9ZLwtuT0$mLoRQuWY/qcxCRWhD1C2M."
  },
  {
    "$md5,rounds=963$er0EceI7$$SdWKu/EgaVvya0m3T4Ml61",
    "$md5,rounds=963$er0EceI7$",
    "$md5,rounds=963$er0EceI7$SdWKu/EgaVvya0m3T4Ml61"
  },
  {
    "$md5$1xMeE.at$$qRpVD46c.sEWM/48tNk191",
    "$md5$1xMeE.at$",
    "$md5$1xMeE.at$qRpVD46c.sEWM/48tNk191"
  },
  {
    "$md5,rounds=4096$1xMeE.at$$XbkZGZUTKzh/i0o7JRKe./",
    "$md5,rounds=4096$1xMeE.at$",
    "$md5,rounds=4096$1xMeE.at$XbkZGZUTKzh/i0o7JRKe./",
  },
  {
    "$md5,rounds=9748$2kkhnoZI$$HzOCKmX2sus/1S9CmohBY/",
    "$md5,rounds=9748$2kkhnoZI$",
    "$md5,rounds=9748$2kkhnoZI$HzOCKmX2sus/1S9CmohBY/"
  },
  {
    "$md5$9ZLwtuT0$$ZRfjIfcFjDekvFzC6wCa2/",
    "$md5$9ZLwtuT0$",
    "$md5$9ZLwtuT0$ZRfjIfcFjDekvFzC6wCa2/"
  },
  {
    "$md5,rounds=5619$9ZLwtuT0$5.D2mO0RKrZtrrBh3fduf.",
    "$md5,rounds=5619$9ZLwtuT0$x",
    "$md5,rounds=5619$9ZLwtuT0$$5.D2mO0RKrZtrrBh3fduf."
  },
  {
    "$md5,rounds=963$er0EceI7$Pt3h1M5TiSImJ4jk663aR/",
    "$md5,rounds=963$er0EceI7$x",
    "$md5,rounds=963$er0EceI7$$Pt3h1M5TiSImJ4jk663aR/"
  },
  {
    "$md5$1xMeE.at$I566aJ9IitIdjKKjZJ8Zo0",
    "$md5$1xMeE.at$x",
    "$md5$1xMeE.at$$I566aJ9IitIdjKKjZJ8Zo0"
  },
  {
    "$md5,rounds=9748$2kkhnoZI$suo2yEVmCZnnnz6ZZHYit0",
    "$md5,rounds=9748$2kkhnoZI$x",
    "$md5,rounds=9748$2kkhnoZI$$suo2yEVmCZnnnz6ZZHYit0"
  },
  {
    "$md5$9ZLwtuT0$UvTt17ajkoa7kwpCrtMeb1",
    "$md5$9ZLwtuT0$x",
    "$md5$9ZLwtuT0$$UvTt17ajkoa7kwpCrtMeb1"
  },
};

#define ntests ARRAY_SIZE (tests)

int
main (void)
{
  struct crypt_data output;
  int result = 0;
  unsigned int i, j;
  char *previous = malloc (sizeof (output.output) + 1);

  for (i = 0; i < ntests; ++i)
    {
      for (j = 0; j < 3; ++j)
        {
          char *cp = crypt_r (password, tests[i][j], &output);
          if ((j == 0) && (strcmp (cp, tests[i][j]) != 0))
            {
              printf ("test %u.%u: expected \"%s\", got \"%s\"\n",
                      i, j, tests[i][j], cp);
              result = 1;
            }
          if ((j == 1) && (strcmp (cp, previous) != 0))
            {
              printf ("test %u.%u: expected \"%s\", got \"%s\"\n",
                      i, j, previous, cp);
              result = 1;
            }
          if ((j == 2) && (strcmp (cp, tests[i][j]) == 0))
            {
              printf ("test %u.%u: \"%s\" was not different from returned hash.\n",
                      i, j, tests[i][j]);
              result = 1;
            }
          strcpy (previous, tests[i][j]);
        }
    }

  free (previous);
  return result;
}

#else

int
main (void)
{
  return 77; /* UNSUPPORTED */
}

#endif
