/* brute.c
 *
 * brute.c is the source file for a VERY brute force passwd checking 
 * utility.  brute checks a cyphertextcreated by crypt() against the words 
 * that are generated from a user-defined character set.
 *
 * by jeff hamblin@cs.wisc.edu
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#define MAX_PW_LENGTH	8

void generate(char *cs, int size, int max, char *pw, char *salt, char *enc);

int main(int argc, char **argv)
{
	FILE *pw_file, *cs_file;
	char *cs_filename, *pw_filename;
	char encrypted[80], salt[3], guess[80], char_set[1024];
	unsigned long count = 0;    
	int i, minimum;
	
	if (argc != 4)
	{
		printf("usage: %s charset_file encrypted_file minimum_length\n",
		argv[0]);
		exit(-1);
	}	

	minimum = atoi(argv[3]);

	/* get the character set */
	cs_filename = argv[1];
	cs_file = fopen(cs_filename, "r");
	if (cs_file == NULL) {
		printf("run: error opening file %s\n", cs_filename);
		exit(-1);
	}
	fgets(char_set, 1024, cs_file);
	fclose(cs_file);

	printf("the character set is: \n");
	for (i = 0; i < strlen(char_set); i ++)
	{
		printf("\t%d (%c)\n", char_set[i], char_set[i]);
	}
	if (char_set[strlen(char_set) - 1] == '\n')
	{
		char_set[strlen(char_set) - 1] = '\0';
	}
	
	/* get the encrypted password to match */
	pw_filename = argv[2];
	pw_file = fopen(pw_filename, "r");
	if (pw_file == NULL) {
		printf("run: error opening file %s\n", pw_filename);
		exit(-1);
	}
	fgets(encrypted, 80, pw_file);
	if (encrypted[strlen(encrypted) - 1] == '\n')
	{
		encrypted[strlen(encrypted) - 1] = '\0';
	}

	strncpy(salt, encrypted, 3);
	salt[2] = '\0';
	fclose(pw_file);

	printf("the encrypted pw to crack is: \"%s\"\n", encrypted);

	for (i = minimum; i < MAX_PW_LENGTH; i ++)
	{
		memset(guess, 0, sizeof(char) * 80); 
		generate(char_set, i, i, guess, salt, encrypted);
	}
}

/* this is a recursive function that will generate all possible
 * strings of a particular length from a defined character set */

void generate(char *cs, int size, int max, char *pw, char *salt, char *enc) 
{
	int i;
	char *enc_guess;

	if (size <= 0)
	{
		enc_guess = (char *)crypt(pw, salt);
		printf("testing \"%s\" with salt \"%s\" -> %s\n", pw, salt,
		enc_guess);
		if (strcmp(enc_guess, enc) == 0)
		{
			printf("* * *\n");
			printf("* * *\n");
			printf("%s decrypts to %s\n", enc, pw);
			printf("* * *\n");
			printf("* * *\n");
			exit(1);
		}
		return;
	}	
	else 
	{
		for (i = 0; i < strlen(cs); i ++)
		{
			pw[max - size] = cs[i];
			generate(cs, size - 1, max, pw, salt, enc);
		}
	}	
}
