#include <iostream>
#include <crypt.h>
#include <cstdio>
#include <ctime>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <omp.h>
/**********************************
FOR TESTING USE:
HASH: X.p6jpj1uDVC0004tuJq0vDkOfGoDPI4pcDZjyGGzQoD4kUwCGGu3Kuu4Ae1r88/exKlEty5yU0CRjx7BbMHq/
SALT: qP/K/YHB
HASH ALGORITHM: 6
Password length: 4
Keyspace: Something containing "t" "e" and "s"
Result should be "test"
Some sample keyspaces:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
**********************************/
int pwdlen; // password length
char *password; // the password
int counter; // password counter for stats
clock_t begin; // clock for time measurement
int nthreads;
using namespace std;
string actual_hash; // the actual hash which shall be matched
string salt; // the salt used in the shadow file
char *keyspace;
struct crypt_data cryptdata;
bool checkpasswd(string pwd);
bool passwordfound = 0;
int loop(int n, char firstletter, char* password, struct crypt_data cryptdata);
int main(int argc, char** argv)
{
if(argc != 7)
{
cout << argv[0] << " <actual Hash> <salt> <pwd length> <hash algorithm> <ncpus> <keyspace>" << endl;
return 1;
}
// Start the clock for performance measurement
begin = clock();
// read the actual hash from the argument list
actual_hash = argv[1];
// read the salt from the argument list
salt = argv[2];
// read the encryption algorithm from the argument list
string encryption(argv[4]); // encryption method(leave blank for DES,'1'= MD5,'2' = Blowfish,'3'=NT-Hash,'5'=SHA-256,'6'=SHA-512)
// create the salt-string in the way the crypt function wants it
salt = "$"+encryption + "$" + salt;
// create the actual-hash-string in the way the crypt function wants it
actual_hash = salt + "$" + actual_hash;
// read the password length from the argument list
pwdlen = atoi(argv[3]);
// initialize the counter of checked passwords
counter = 0;
// read the desired number of threads from the argument list
nthreads = atoi(argv[5]);
// initialize open mp threads
omp_set_num_threads(nthreads);
// read the keyspace from the argument list
keyspace = argv[6];
// calculate maximum number of passwords that have to be checked
unsigned long numpwd = pow(strlen(keyspace),pwdlen);
// write maximum number of passwords that have to be checked
cout << "Checking "<< numpwd << " passwords..."<<endl;
// first letter of prospective password (to enable parallelization)
char firstletter;
// define conditions for open mp parallelization
#pragma omp parallel for private(firstletter, password, passwordfound, cryptdata) shared(keyspace, pwdlen, counter) default(none)
// cycle through the first letter and using multiple threads
for(int k=0; k<strlen(keyspace); k++) {
// what does that structure do?
struct crypt_data cryptdata;
cryptdata.initialized = 0;
// allocate memory for the password that will be checked
password = new char [pwdlen];
// set the first letter of the password
firstletter = keyspace[k];
// start the password-create-loop
loop(pwdlen-1,firstletter,password,cryptdata);
}
// we arrive here only when no password has been found
clock_t end = clock();
// calculate and write elapsed seconds
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC / nthreads;
cout << "No password found"<< "\nStats: "<< numpwd<< " passwords in "<< elapsed_secs << " seconds\n"<<counter/elapsed_secs << " passwords per second"<< endl;
return 1;
}
int loop(int n, char firstletter, char* password, struct crypt_data cryptdata)
{ // loops through the possible combination of charachters in the keyspace
// this function will call itself until the password has the desired length
// the string for the password that will be checked
string chkpwd;
// until we arrive at the last charachter...
if(n>=0)
{
for ( int i=0; i<strlen(keyspace); i++)
{
// set the n-th charachter of the password ...
password[n] = keyspace[i];
// ... and call this very function again
loop(n-1, firstletter,password, cryptdata);
}
if(n==0)
{ // in the last iteration...
// ...build password. Start with the first letter...
chkpwd=firstletter;
// ... and append the others
for(int j=1;j<pwdlen;j++)
{
chkpwd += password[j];
}
// find out the thread-id
const int id = omp_get_thread_num();
// increase number of checked passwords
counter ++;
// string for the hash that correspons to the password that is being checked right now
string checkhash;
// check whether prospective password's hash fits:
checkhash = crypt_r(chkpwd.c_str(), salt.c_str(), &cryptdata);
passwordfound = ( checkhash == actual_hash );
// if the password has been found ...
if ( passwordfound )
{
// ... print password, statistics about the performance and exit
cout << chkpwd << " " << id << "\n";
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC / nthreads;
printf("****** Thread %i: Password found: %s ****** \n",id,chkpwd.c_str());
printf("Thread %i: Stats: %i passwords in %f seconds\n",id,counter, elapsed_secs);
printf("Thread %i: %f passwords per second",id, counter/elapsed_secs);
exit(0);
}
// clear password for the next run
chkpwd.clear();
}
}
}