Commit 1bd2cc35 authored by clement's avatar clement

Initial commit for SHA1BruteForce

parents
hash.dat
*.o
sha1
*~
gmon.out
a.out
*.s
err
*.gcda
This diff is collapsed.
# SHA1BruteForce, brute-force attack to recover SHA-1 hashed password.
# Copyright (C) 2017 Clément Février
#
# 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, either version 3 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Contact informations:
# Email
# clement+dev@forumanalogue.fr
# Post address
# 4 impasse de l'Abbaye
# 38100 Grenoble
# FRANCE
all:ex
# Safe
# It should not display any warning.
# -Ofast activates some optimization flags.
# Other flags are added.
# -pipe decreases compilation time.
#
CC= g++ -Ofast -Wall -Wextra -pipe -fassociative-math -freciprocal-math -fno-signed-zeros -fno-trapping-math -frename-registers -funroll-loops -fopenmp -D_GLIBCXX_PARALLEL
#
# Same as above with flags specific for AMD Piledriver Family 15h.
#
#CC= g++ -Ofast -Wall -Wextra -pipe -fassociative-math -freciprocal-math -fno-signed-zeros -fno-trapping-math -frename-registers -funroll-loops -fopenmp -D_GLIBCXX_PARALLEL -march=bdver2 -msse -msse2 -msse3 -mmmx -m3dnow
#
# Use -fprofile-generate to generate a profile.
# Here for AMD Piledriver Family 15h.
#
#CC= g++ -Ofast -Wall -Wextra -pipe -fassociative-math -freciprocal-math -fno-signed-zeros -fno-trapping-math -frename-registers -funroll-loops -fopenmp -D_GLIBCXX_PARALLEL -march=bdver2 -msse -msse2 -msse3 -mmmx -m3dnow -fprofile-generate
#
# Use -fprofile-use -fprofile-correction to use the profile.
# The second flag is needed for multithreading.
# Here for AMD Piledriver Family 15h.
#
#CC= g++ -Ofast -Wall -Wextra -pipe -fassociative-math -freciprocal-math -fno-signed-zeros -fno-trapping-math -frename-registers -funroll-loops -fopenmp -D_GLIBCXX_PARALLEL -march=bdver2 -msse -msse2 -msse3 -mmmx -m3dnow -fprofile-use -fprofile-correction
link= -o
arg= -c -o
#lib= -lboost_thread -lboost_system -lcrypto++
lib= -lboost_thread -lboost_system -ltomcrypt
objets= main.o functions.o
ex: ${objets}
@${CC} ${link} sha1 ${objets} ${lib}
%.o: %.cpp
@${CC} ${arg} $@ $< ${lib}
clean:
@rm -f *~ *.o gmon.out a.out *.s
mrproper: clean
@rm -f sha1 err *.gcda
SHA1BruteForce, brute-force attack to recover SHA-1 hashed password.
Copyright (C) 2017 Clément Février
1/ License
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, either version 3 of the License, or
(at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact informations:
Email
clement+dev@forumanalogue.fr
Post address
4 impasse de l'Abbaye
38100 Grenoble
FRANCE
2/ About
This is a simple C++ software to recover a password
for SHA-1 hash. It is performing a brute-force attack.
Complexity: It is a simple brute-force algorithm,
so the complexity increases exponentially
with the size of the password.
Multithreading: On a N_CORE computer,
if SEQTIME is the maximum time
when launched with one thread,
then the maximum time is
SEQTIME / N_TREAD when N_THREAD < N_CORE
and SEQTIME / N_CORE when N_THREAD > N_CORE
3/ Install
You need gcc < 8, Boost and Libtomcrypt.
The restriction comes from an incompatibility between GCC 8
and Boost.
On Ubuntu,
$ sudo apt install g++ libboost-all-dev libtomcrypt-dev
4/ Use
4.1/ main.cpp
Modify the parameters in main.cpp.
* HASH: The SHA-1 hash.
Two accepted format:
1/ Without spaces, as usually stored.
You need to ensure
that it is 40 character-long.
Example for the password ZZZ
116ff222a3b49b63348d7782e4b43ffe2dcbb198
2/ With spaces.
No restriction on the length of the string.
But you need to ensure to have
20 spaced-separated hexadecimal numbers.
It is the format used to display hashes
in this program.
Example for the password ZZZZZZ
18 f3 f 1b a4 c6 2e 2b 46 e 69 33 6 b3 9a d e2 7d 74 7c
* MaxLength: Maximum length of the password to test.
* N_THREAD: Number of threads to launch.
The program will launch at most
a number of thread corresponding
to the number of character to test.
In other words, the length of list.
In this case, it is 95. */
4.2/ Makefile
4.2.1/ (Optional) Profiling
You can use the Makefile as it is,
but I recommend to add the flags specific to your architecture.
Also, you can profile the code with the following steps.
Set the variable test in main.cpp. For example, change line 91
const std::string test = "";
to
const std::string test = "!!!";
Add the flag -fprofile-generate
to the variable CC in the Makefile.
Clean object in case already compile before
and recompile with the new flag.
$ make clean; make -j 2
Execute the code to generate the profile.
$ ./sha1
Modify main.cpp to reverte back test to ""
otherwise the SHA-1 hash that you want to crack will be ignore.
Modify the variable CC in the Makefile
to substitute -fprofile-generate
by -fprofile-use -fprofile-correction.
4.2.2/ Compiling
Then compile with
$ make
or
$ make -j 2
for parallel compiling.
Any number greater than 2 will not have effect
because there is only 2 objects.
4.3/ sha1
Launch it with
./sha1
It will display the SHA-1 hash and the corresponding password
if it find it.
/*
SHA1BruteForce, brute-force attack to recover SHA-1 hashed password.
Copyright (C) 2017 Clément Février
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, either version 3 of the License, or
(at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact informations:
Email
clement+dev@forumanalogue.fr
Post address
4 impasse de l'Abbaye
38100 Grenoble
FRANCE
*/
//#include <crypto++/sha.h>
//#include <crypto++/hex.h>
#include <string> // std::string
#include <iostream> // std::cout
#include <ostream> // std::endl
#include <cstddef> // size_t
#include <cstdio> // std::printf
#include <cstdlib> // EXIT_SUCCESS, exit
#include <boost/thread.hpp> // boost::thread_group, boost::bind
#include <tomcrypt.h> // sha1_desc, hash_state, sha1_init, sha1_process
#include "functions.h"
/**
* Hashes a given input string using the SHA1 algorithm
* @param input The input sequence pointer
* @param inputSize The size of the input sequence
* @return A new[]-allocated pointer to the resulting data. 20 bytes long.
*/
unsigned char * hashSHA1(const std::string & input)
{
//Initial
unsigned char * hashResult = new unsigned char[sha1_desc.hashsize];
//Initialize a state variable for the hash
hash_state md;
sha1_init(&md);
//Process the text - remember you can call process() multiple times
sha1_process(&md, (const unsigned char*) input.c_str(), input.size());
//Finish the hash calculation
sha1_done(&md, hashResult);
// Return the result
return hashResult;
}
/*std::string generateHash(const std::string & source)
{
CryptoPP::SHA1 hash;
byte digest[CryptoPP::SHA1::DIGESTSIZE];
hash.CalculateDigest(digest, (const byte*)source.c_str(), source.size());
std::string output;
CryptoPP::HexEncoder encoder;
CryptoPP::StringSink test = CryptoPP::StringSink(output);
encoder.Attach(new CryptoPP::StringSink(output));
encoder.Put(digest, sizeof(digest));
encoder.MessageEnd();
return output;
}*/
void findPassword(const unsigned char * hash, const std::string * list, const unsigned int & COUNT, const unsigned int & L, const unsigned int N_THREAD)
{
// Create a group of threads
boost::thread_group t;
for(unsigned int i = 0; i < COUNT; ++i)
{
// Launch a thread
// Initiate the recursive function with the first letter
t.create_thread(boost::bind(findPasswordThread, hash, list[i], list, COUNT, L, 1, N_THREAD));
// Wait until N_THREAD finish before launching news ones
if((i % N_THREAD) == (N_THREAD - 1))
{
// Do not continue before all launched threads finish
t.join_all();
// Display a progress to standard output
std::cout<<"progress: "<<100 * i / (double)COUNT <<"%"<<std::endl;
}
}
// Wait for remaining threads to finish
t.join_all();
}
void findPasswordThread(const unsigned char * hash, const std::string & pass, const std::string * list, const unsigned int & COUNT, const unsigned int & L, const unsigned int & l, const unsigned int N_THREAD)
{
// If the password to test is build,
// test if it is the correct one
if(l == L)
{
// Hash the pass word to test
unsigned char * sha1 = hashSHA1(pass);
// Test if hashes match
// Assume that the correct password expected if shown otherwise
bool found = true;
for(size_t i = 0; i < 20; ++i)
{
// This condition is strictly equivalent to
// if(sha1[i] ^ hash[i])
// They need -O3 to be efficient
// because it is reduced from 16 to only 3 instructions
// in assembler.
// Extra labels of -Ofast does not affect this instruction.
if(sha1[i] != hash[i])
{
found = false;
// If is not a match, there is no need to keep testing.
break;
}
}
// Free the memory of the test hash
// because it is not needed anymore.
delete [] sha1;
// If it is a match, then display the password and hash,
// and exit the program as there is not need to keep looking
// for the password.
// It is not thread safe,
// so we cannot free the memory of the variable hash
// otherwise other threads will try to access the pointer
// leading to a segmentation fault.
if(found)
{
// Display once again the hash.
std::cout<<"* Hash SHA1:"<<std::endl;
for (int x = 0; x < 20; x++) {
std::printf("%x ", hash[x]); //Hex-format
}
std::cout<<std::endl;
// Display the password.
std::cout<<"* Password:"<<std::endl<<pass<<std::endl;
// Exit the program regardless the state of the other threads.
exit(EXIT_SUCCESS);
}
}
else
{
// If the password is not build yet,
// keep appending characters.
for(unsigned int i = 0; i < COUNT; ++i)
{
// pass + list[i]
// adds a new letter to the password to test.
// Increment l + 1
// because a new character is added to the password to test.
findPasswordThread(hash, pass + list[i], list, COUNT, L, l + 1, N_THREAD);
}
}
}
/*
SHA1BruteForce, brute-force attack to recover SHA-1 hashed password.
Copyright (C) 2017 Clément Février
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, either version 3 of the License, or
(at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact informations:
Email
clement+dev@forumanalogue.fr
Post address
4 impasse de l'Abbaye
38100 Grenoble
FRANCE
*/
/* Return the hash SHA-1 of a string (input)
using libtomcrypt */
unsigned char * hashSHA1(const std::string & input);
/* Return the hash SHA-1 of a string (source)
using Crypto++ */
//std::string generateHash(const std::string & source);
/* Seek for password, display the latter if found it
and exit the program.
This function launch the threads that will do the job.
Depending on the number of threads,
Each thread will test a different subset of possibilities.
As a consequence,
a greater or smaller number of threads can divide
the set of possibilities in a way that it will reach faster
or slower the actual password.
However, there is noway to make an assumption on this number
if there is no assumption on the password.
Thus, the number of thread should be tuned
to maximize device performances,
i.e. the greatest number of operations per second.
Parameters:
* hash: The hash to crack.
* list: List of all allowed characters.
* COUNT: Length of list.
* L: Maximum length of the password to test.
* N_THREAD: Number of threads to launch. */
void findPassword(const unsigned char * hash, const std::string * list, const unsigned int & COUNT, const unsigned int & L, const unsigned int N_THREAD);
/* Seek for password, display the latter if found it
and exit the program.
Parameters:
* hash: The hash to crack.
* pass: Current state of the password to build and test.
* list: List of all allowed characters.
* COUNT: Length of list.
* L: Maximum length of the password to test.
* l: Current length of the password to test.
* N_THREAD: Number of threads to launch. */
void findPasswordThread(const unsigned char * hash, const std::string & pass, const std::string * list, const unsigned int & COUNT, const unsigned int & L, const unsigned int & l, const unsigned int N_THREAD);
/*
SHA1BruteForce, brute-force attack to recover SHA-1 hashed password.
Copyright (C) 2017 Clément Février
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, either version 3 of the License, or
(at your option) any later version.
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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact informations:
Email
clement+dev@forumanalogue.fr
Post address
4 impasse de l'Abbaye
38100 Grenoble
FRANCE
*/
#include <string> // std::string
#include <sstream> // std::istringstream
#include <vector> // std::vector
#include <ios> // std::hex
#include <iostream> // std::cout
#include <ostream> // std::endl
#include <cstdio> // std::printf
#include "functions.h" // findPassword
/* Seek for a password corresponding to a given SHA-1 hash.
Complexity: It is a simple brute-force algorithm,
so the complexity increases exponentially
with the size of the password.
Multithreading: On a N_CORE computer,
if SEQTIME is the maximum time
when launched with one thread,
then the maximum time is
SEQTIME / N_TREAD when N_THREAD < N_CORE
and SEQTIME / N_CORE when N_THREAD > N_CORE
Parameters to set before compiling:
* HASH: The SHA-1 hash.
Two accepted format:
1/ Without spaces, as usually stored.
You need to ensure
that it is 40 character-long.
Example for the password ZZZ
116ff222a3b49b63348d7782e4b43ffe2dcbb198
2/ With spaces.
No restriction on the length of the string.
But you need to ensure to have
20 spaced-separated hexadecimal numbers.
It is the format used to display hashes
in this program.
Example for the password ZZZZZZ
18 f3 f 1b a4 c6 2e 2b 46 e 69 33 6 b3 9a d e2 7d 74 7c
* MaxLength: Maximum length of the password to test.
* N_THREAD: Number of threads to launch.
The program will launch at most
a number of thread corresponding
to the number of character to test.
In other words, the length of list.
In this case, it is 95. */
int main ()
{
// Number of threads to launch.
const unsigned int N_THREAD = 64;
// Max length of password.
const unsigned int MaxLength = 4;
// SHA-1 hash to crack.
// Below few examples and their corresponding password.
// ZZZ
//std::string HASH = "11 6f f2 22 a3 b4 9b 63 34 8d 77 82 e4 b4 3f fe 2d cb b1 98";
std::string HASH = "116ff222a3b49b63348d7782e4b43ffe2dcbb198";
// ZZZZ
//std::string HASH = "98 65 d4 83 bc 5a 94 f2 e3 0 56 fc 25 6e d3 6 6a f5 4d 4";
// ZZZZZ
//std::string HASH = "f8 88 fa 8a 61 ba 9a 53 a4 5f 4 a 4b bb 8b 2f c1 f6 44 44";
// ZZZZZZ
//std::string HASH = "18 f3 f 1b a4 c6 2e 2b 46 e 69 33 6 b3 9a d e2 7d 74 7c";
//std::string HASH = "18 f3 f 1b a4 c6 2e 2b 46 e 69 33 6 b3 9a d e2 7d 74 7c";
// If set, ignore HASH and compute test's SHA-1 hash and attempt to crack it.
const std::string test = "";
// Pointer used to store the SHA-1 hash.
unsigned char * hash;
// std::vector used to create hash.
// Warning: It cannot be put inside the else's scope
// otherwise the pointer is destroyed when leaving it.
std::vector< unsigned char > bytes;
// If a password is manually set,
// then generate its SHA-1 hash and attempt to crack it.
// It can be used for testing and benchmarking purposes.
if(test != "")
{
std::cout<<"* Test password:"<<std::endl;
std::cout<<test<<std::endl;
//const std::string hash = generateHash(test);
// Generate the SHA-1 hash of test.
hash = hashSHA1(test);
}
else
{
// Convert HASH to the correct format if needed.
// Only start to search for space at position 37.
// If find() return std::string::npos,
// then find() did not find any space.
if(HASH.find(" ", 37) == std::string::npos)
{
// Add space every 2 characters starting from the end.
std::string space = " ";
for(size_t i = 19; i > 0; --i)
{
HASH.insert(2 * i, space);
}
}
// Convert HASH from std::string to unsigned char *.
std::istringstream hex_chars_stream(HASH);
unsigned int c;
while (hex_chars_stream >> std::hex >> c)
{
bytes.push_back(c);
}
// Extract the pointer to the SHA-1 hash
// from the std::vector container.
hash = bytes.data();
}
// Display the input SHA-1 hash.
std::cout<<"* Hash SHA1:"<<std::endl;
for (int x = 0; x < 20; x++)
{
std::printf("%x ", hash[x]); //Hex-format
}
std::cout<<std::endl;
// list: Create the list of all characters to test.
std::string * list = new std::string [127 - 33 + 1];
// count: Increment used to access list element in the loop.
// Also used to pass the length of the list
// to findPassword.
unsigned int count = 0;
// First item is "".
// Used to build password to test smaller than MaxLength.
list[0] = "";
// Increment count;
count = 1;
// Assign all possible char to list.
// In this case, all from 33 to 126 included.
// The reverted order is used to test in priority
// lowercase-based passwords.
for(unsigned int i = 126; i > 32; --i)
{
// Convert the dec value of i to char.
list[count] = (char)i;
// Increment count.
++count;
}
// Find the password, display and exit if found it.
// 2 possible reasons it does not find it:
// 1/ The password length is greater than MaxLength.
// 2/ The list does not contain at least one character
// of the password.
findPassword(hash, list, count, MaxLength, N_THREAD);
// Exit without error.
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment