Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
6005-Solutions/HashCracker/test_proper_salt.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
150 lines (105 sloc)
4.01 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Test Cases and Demo code for Salted Hashed | |
""" | |
import unittest | |
import time | |
import hashlib | |
TARGETS = ["rkKxLR$c35bf00b953186ec3be4916dd45deabc", | |
"MyEtoS$b0a56a1df2353c7629509a12a17f5a2d", | |
"kshhHk$9664b09bedf4ed95f1b7b024087cec12", | |
"FMVbrf$6751d1e9a8ee57b383836596869cd94a", | |
"wKBUOm$981132067d1a4ef9e943b8c300071a55" | |
] | |
CORRECT_WORDS = ["coffee","azerty","spitfire", "f00tball","1qazxsw23edc"] | |
CORRECT_MATCHES = dict(zip(TARGETS, CORRECT_WORDS)) | |
# CORRECT_MATCHES = {'283140d63e0937fb652ff7066bbf5c2f': 'coffee', | |
# 'ba7c94b0431f30103c7eb5cdae180be6': 'azerty', | |
# 'ff0e0cefdceb54618f47767d17b95a12': 'spitfire', | |
# 'ef98a984f8ab1341039f9f3344d80298': 'f00tball', | |
# '25e2262b5d8c95f7ece0bc4f30f5213d': '1qazxsw23edc'} | |
def extractSalt(theHash): | |
""" | |
Break a Salted Hash into its compoenents. | |
We are using the convention of <salt>$<hash> | |
so can simply split on $ | |
@return: Tuple of [salt, hash] | |
""" | |
return theHash.split("$") | |
#And modify the function with lookups we used before | |
def applySalt(plaintext, salt): | |
""" | |
Apply some Salt to the plaintext | |
""" | |
return "{0}{1}".format(plaintext, salt) | |
def crackHash_Salt(wordlist, target): | |
""" | |
This time we have a list of salted hashes. | |
It means we can no longer take the approach we used before, of | |
cracking all hashes and stashing in a dictionary. | |
Instead we extract the salt, append it to each of the items in the wordlist | |
Then check if we get a match | |
""" | |
#Fetch the Salt from the first item | |
theSalt, targetNoSalt = extractSalt(target) | |
#print("Extract Salt {0} and Hash {1}".format(theSalt, targetNoSalt)) | |
#Go through the wordlist and get the hash for each item. | |
for plaintext in wordlist: | |
plaintext = plaintext.strip() | |
saltedText = applySalt(plaintext, theSalt) | |
theHash = hashlib.md5(saltedText.encode()).hexdigest() | |
#Store in the "Database" | |
if theHash == targetNoSalt: | |
return plaintext | |
def crackList_Salt(wordlist, targets): | |
""" | |
Use the strategy above to crack a list of passowords that have been salted | |
As we cant store we just iterate through the list, and collect the details | |
""" | |
matches = {} | |
for item in targets: | |
cracked = crackHash_Salt(wordlist, item) | |
matches[item] = cracked | |
return matches | |
class TestCases(unittest.TestCase): | |
@classmethod | |
def setUpClass(cls): | |
""" | |
A bit of magic to keep the stats. | |
Called the first time the class is run | |
""" | |
cls.statsDict = {} | |
@classmethod | |
def tearDownClass(cls): | |
""" | |
And a bit more magic to print the stats. | |
""" | |
print("\n\n{0} STATS (Salted) {0}".format("-"*20)) | |
print("Crack Single Salted : {0}".format(cls.statsDict["singleSalt"])) | |
print("Crack List of Salted: {0}".format(cls.statsDict["saltList"])) | |
def setUp(self): | |
""" | |
Load the wordlist each time we run a test case | |
Here we open the wordlist file, then store it as an array | |
This lets us reuse the list multiple times | |
""" | |
with open("10-million-password-list-top-10000.txt") as fd: | |
#Store as an array | |
self.wordlist = fd.readlines() | |
def testSingle_ProperSalt(self): | |
""" | |
Check how long it takes to crack a single salted hash | |
""" | |
t1 = time.time() | |
out = crackHash_Salt(self.wordlist, TARGETS[0]) | |
t2 = time.time() | |
self.assertEqual(out, "coffee") #check we were successful | |
self.statsDict["singleSalt"] = t2-t1 | |
def testList_ProperSalt(self): | |
""" | |
And Crack a list of salted passwords | |
""" | |
t1 = time.time() | |
out = crackList_Salt(self.wordlist, TARGETS) | |
t2 = time.time() | |
self.assertEqual(out, CORRECT_MATCHES) #check we were successful | |
self.statsDict["saltList"] = t2-t1 | |