#include "includes.h"

void str_to_key(unsigned char *str,unsigned char *key);
void usage(char *progname);
void fill_user_struct(int, char *dastring, struct user_struct *da_struct);
void LMword(char *passwd, char *word);
char *atob(char *hexstring,int size);
int htoi(char c);
int PutUniCode(char *dst,char *src);
int isvalid_userline(int, char *str);

/*
 * Convert a 7 byte array into an 8 byte des key with odd parity.
 */

void str_to_key(unsigned char *str,unsigned char *key)
{
	void des_set_odd_parity(des_cblock *);
	int i;

	key[0] = str[0]>>1;
	key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
	key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
	key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
	key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
	key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
	key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
	key[7] = str[6]&0x7F;
	for (i=0;i<8;i++) {
		key[i] = (key[i]<<1);
	}
	des_set_odd_parity((des_cblock *)key);
}


void usage(char *progname){
   char *p;

   p = strrchr(progname, '\\');
   if (p == NULL)
	p = progname;
   else
	p++;

   fprintf(stderr, "Usage: %s -p <pwfile> -w <wordlist> -o <ofile> -b"
		" [-l || n]\n", p);
   fprintf(stderr, "     -p <pwfile> The password file to read from in pwdump format\n");
   fprintf(stderr, "     -P <pwfile> The password file to read from in sniffer format\n");
   fprintf(stderr, "     -w <wordlist> The dictionary of words to try\n");
   fprintf(stderr, "     -o <ofile> File to write results to - if not\n");
   fprintf(stderr, "                specified defaults to stdout\n");
   fprintf(stderr, "     -b Brute force through the entire keyspace\n");
   fprintf(stderr, "          <A-Z takes 26 hours on PPRO 200>\n");
   fprintf(stderr, "     -l Only go after the LANMAN password\n");
   fprintf(stderr, "     -n Only go after the NT Dialect password [dumb!]\n");
   fprintf(stderr, "          without the -l or -n it goes after both\n");
   fprintf(stderr, "          which is still much faster than going after\n");
   fprintf(stderr, "          the NT Dialect password only!\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "  Note: Both -p and -w are required, unless -b is"
		" specified\n");
   fprintf(stderr, "        in which case -w must be ommited\n");
   fprintf(stderr, "             mudge@l0pht.com\n");
   exit(1);
}

void fill_user_struct(int pwdump, char *dastring, struct user_struct *da_struct){
	char *tmp, *atobstr;

        /* clear out the sucker */
	memset(da_struct, '\0', sizeof(struct user_struct)); 

	da_struct->pwdumpval = pwdump;

  if (pwdump){
    strncpy(da_struct->username, strtok(dastring, ":"), 128);
    strtok(NULL, ":"); /* skip over UID */
    tmp = strtok(NULL, ":");
    if (strncmp(tmp, "NO PASSWORD", 11) == 0){
      strcpy(da_struct->lmhash, "DISABLED?");
      strcpy(da_struct->nthash, "DISABLED?");
    } else if (strncmp(tmp, "********", 8) == 0){
        strcpy(da_struct->lmhash, "NULL PASSWD?");
        strcpy(da_struct->nthash, "NULL PASSWD?");
    } else {
        strncpy(da_struct->lmhash, tmp, 32);
        strncpy(da_struct->nthash, strtok(NULL, ":"), 32);
    }

    if ((strncmp(da_struct->lmhash, "DISABLED?", 9) != 0) \
           && (strncmp(da_struct->lmhash, "NULL PASSWD?", 12) != 0 )){
      atobstr = atob(da_struct->lmhash, 32);
      memcpy(da_struct->lmhashb, atobstr, 16);
      free(atobstr);

      atobstr = atob(da_struct->nthash, 32);
      memcpy(da_struct->nthashb, atobstr, 16);
      free(atobstr);
    }

    /* if the second part of the lanman key is 0xAAD3B435B51404EE then 
           the password is 7 chars or less and we don't need to spin the 
           extra CPU cycles */
    if (memcmp(&(da_struct->lmhash[16]), "AAD3B435B51404EE", 16) == 0)
      da_struct->under7 = 1;
    else
      da_struct->under7 = 0;
  } else { /* we are reading from a sniffer file */
    strncpy(da_struct->username, strtok(dastring, ":"), 128);
    tmp = strtok(NULL, ":"); /* get the password length */
    if (atoi(tmp) >= 7)
      da_struct->under7 = 0;
    else
      da_struct->under7 = 1;

    tmp = strtok(NULL, ":"); /* get the 8byte challenge - note that we
                                have it stored in ascii so it is 16 bytes
                                to begin with */
    atobstr = atob(tmp, 16);
    memcpy(da_struct->server_chall, atobstr, 8);
    free(atobstr);

    tmp = strtok(NULL, ":");
    atobstr = atob(tmp, 48);
    memcpy(da_struct->lmresp_b, atobstr, 24);
    free(atobstr);

    tmp = strtok(NULL, ":");
    atobstr = atob(tmp, 48);
    memcpy(da_struct->ntresp_b, atobstr, 24);
    free(atobstr);
  }

  da_struct->lmdone = 0;
  da_struct->ntdone = 0;
  da_struct->already_printed = 0;

  da_struct->next = NULL;
  da_struct->previous = NULL;

}

void LMword(char *passwd, char *word){
	size_t i;
	int word_len;

	word_len = strlen(word);

	for (i=0; i < word_len; i++)
		word[i] = toupper(word[i]);

	if (word_len < 14){
		memcpy(passwd, word, strlen(word));
		for (i=0; i<= (strlen(passwd)); i++){
		  if ((passwd[i] == '\r') || (passwd[i] == '\n'))
			passwd[i] = '\0';
		}
	}
	else
		memcpy(passwd, word, 14);
}

/* the routines atob() and htoi() were lifted from code by
   Josh Daymont - with only minor modifications */
char *atob(char *hexstring,int size) {
    int i, value;
    unsigned char c;
	char *str1, *str2;

    value = (size/2)+1;
	str1 = (char *)(malloc((unsigned)value));
    str2 = str1; /* save pointer to beginning */
	for (i=0; i<size-1; i+=2){
      if((value = htoi(*hexstring++)) == -1)
	     return(0); 
      c = value << 4;
      if((value = htoi(*hexstring++)) == -1)
        return(0);
      c |= value;
      *str1++ = (char)c;
    }
    return(str2);
}

int htoi(char c)
{
        if (c == 32) return(0);
        if('0' <= c && c <= '9')
                return c - '0';
        if('a' <= c && c <= 'f')
                return 10 + c - 'a';
        if('A' <= c && c <= 'F')
                return 10 + c - 'A';
        return -1;
}

/*******************************************************************
write a string in unicoode format
********************************************************************/
int PutUniCode(char *dst,char *src)
{
  int ret = 0;
  while (*src) {
    dst[ret++] = src[0];
    dst[ret++] = 0;    
    src++;
  }
  dst[ret++]=0;
  dst[ret++]=0;
  return(ret-2); /* the way they do the md4 hash they don't represent 
		    the last null. ie 'A' becomes just 0x41 0x00 - not 
		    0x41 0x00 0x00 0x00 */
}

/* quick scan of line read from password file and a return of 1 if it's 
   superficially valid, 0 otherwise - This should really be flushed out 
   and made more intelligent */
int isvalid_userline(int pwdump, char *str){
	unsigned int i, counter;
	
	counter = 0;

        for (i=0; i < strlen(str); i++){
	  if (str[i] == ':')
		counter++;
	  }

#ifdef _DEBUG
  if (pwdump)
    fprintf(stderr, "file is a pwdump file and line has %d delimiters\n", \
                                                                      counter);
  else
    fprintf(stderr, "file is a sniffer file and line has %d delimiters\n", \
                                                                     counter); 
#endif

	if ((pwdump && (counter == 6)) || (!(pwdump) && (counter == 4)))
	    return(1);
	else
	    return(0);
}

