/*****************************************************************************
*
*  autor: Daniel Lerch Hostalot
*	url: http://daniellerch.com  
*
******************************************************************************
*
*  DESCRIPCIÓN:
*  Sistema de desencriptación de contraseñas de Linux mediante fuerza bruta.
*  Prueba combinaciones de letras hasta la longitud máxima, especificada en
*  PASSWD_LENGTH. Para contraseñas de más de 7 caracteres el tiempo resulta
*  excesivo. Coge las contraseñas enctriptadas de un archivo pasado como
*  parámetro.
*
******************************************************************************
*
*	Compilación:
*	$ gcc cracker.c -o cracker -lcrypt
*
*****************************************************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <crypt.h>

#define ASCII_MIN 33			/* Número inicial en la tabla ascii */
#define ASCII_MAX 126		/* Número final en la tabla ascii */
#define PASSWD_LENGTH 10	/* Longitud máxima del password */

/* Cadena donde se almacena el password antes de cada encriptación */
char password_string[PASSWD_LENGTH];

/* Cadena donde se almacena el código ascii de cada carácter */
int  password[PASSWD_LENGTH];

/* Definición de fuinciones */
int brute_force_loop(int col, char *encrypted_pass);

/* Función de desencriptación */
int linux_crypt (char *password_string, char *encrypted_pass);



/*****************************************************************************
*  Función principal 
*****************************************************************************/
int main (int argc, char **argv) {

	if (argc != 2) {

		printf ("Uso: %s password.txt\n",argv[0]);
		exit (0);
	}


	FILE *file;
	char buffer[34];

	/* Apertura del fichero de contraseñas */
	file = fopen (argv[1], "r");
	if (!file) {

		perror ("fopen()");
		exit(0);
	}
	
	while (!feof(file)) {
		
		fscanf (file, "%s", buffer);
		brute_force_loop(PASSWD_LENGTH, buffer);
		getchar();
	}

	fclose(file);
	
	return 0;
}


/****************************************************************************** 
 *  Bucle que genera todas las combinaciones posibles de los carácteres
 *  situados entre ASCII_MIN y ASCII_MAX. Para cada combinación comprueba
 *  si el texto encriptado es el buscado 
 ******************************************************************************/
int brute_force_loop (int col, char *encrypted_pass) {
	
	int i;
	int res=0;

        for ( password[col]=ASCII_MIN-1;
	      password[col]<ASCII_MAX+1;
	      password[col]++) {
	
		if (col != 0) res = brute_force_loop (col - 1, encrypted_pass);
		else {
			memset (password_string, '\0', sizeof(password_string));   
			for (i=0;i<PASSWD_LENGTH;i++) 
				if (password[i]>=ASCII_MIN) 
					password_string[i] = password[i];

			
			printf ("%s\n", password_string);
			if (linux_crypt (password_string,encrypted_pass)==1) {
				
				printf ("Encontrado: %s\n", password_string);
				return 1;
			}
		}
		if (res == 1) return 1;
	}
	return 0;
}


/******************************************************************************
*  Función de encriptación para las contraseñas shadow de Linux
******************************************************************************/ 
int linux_crypt (char *password_string, char *encrypted_pass) {
	
	char *encrypted;
	
	encrypted = crypt (password_string, encrypted_pass); 
	
	if (strcmp (encrypted, encrypted_pass) == 0)  return 1;
	else return -1;
}





