before hashing and before comparing it to the hash passed into the function.
Here is the full instruction.
The function should take an optional second argument named use_salts . If set to true, each salt string from the file known-salts.txt should be appended AND prepended to each password from top-10000-passwords.txt before hashing and before comparing it to the hash passed into the function.
I think I am doing it correctly for the former, which is to use salt for creating a hash, but I am not sure what to do for the latter.
Please help!
Your code so far
def crack_sha1_hash(hash, use_salts=False):
with open('top-10000-passwords.txt', 'r') as f:
if use_salts:
with open('known-salts.txt', 'r') as f2:
for salt in f2:
# removing the trailing new line char
salt = salt.splitlines()[0]
for password in f:
# removing the trailing new line char
password = password.splitlines()[0]
# prepend and append the salt before hashing
guessed_hash = hashlib.sha1((salt + password + salt).encode()).hexdigest()
# Use the salt like this???
guessed_hash = hashlib.sha1((salt + guessed_hash + salt).encode()).hexdigest()
if hash == guessed_hash:
return password
else:
... code for without salt ...
return "PASSWORD NOT IN DATABASE"
Your browser information:
User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36.
This probably could be worded better. Salt is expected to be either prepended or appended to the password, but not in a single guess. From single password you get two cases one with salt prepended, another with the salt appended. After that both can be compared with the hash.
I understand that there are two possibilities of how salt is used for creating a hash:
salt + plain_password, and
plain_password + salt.
So, I tried both as the following but not working correctly. Where am I doing wrong??
for password in f:
# removing the trailing new line char
password = password.splitlines()[0]
# Try prepending the salt before hashing
guessed_hash_prepending = hashlib.sha1((salt + password).encode()).hexdigest()
if hash == guessed_hash_prepending:
return password
# Try appending the salt before hashing
guessed_hash_appending = hashlib.sha1((password + salt).encode()).hexdigest()
if hash == guessed_hash_appending:
return password
Salting part is now correct, but there’s something else, more tricky, going on. One thing needed to remember is once file is opened, the open function doesn’t return string or list, but a file-like object (also called as a stream).
It behaves differently than those typical types, so once, for certain salt, password file is iterated (with for password in f:), the position in the file is the ending and it doesn’t return automatically to the beginning. For the next salt, code inside of loop for password in f: will not be executed because trying to iterate file again will return StopIteration exception on the first iteration.
To summarize what is happening:
Iterator for salts file gets first salt
Iterator for password file gets every password one by one, which is checked with first salt prepended and appended, but doesn’t find match
Iterator for salts file gets second salt
Iterator for password file doesn’t return anything and no actual checks for second salt is done
Iterator for salts file gets third salt
(And so on…)
File object has actually seek() method that allows to move back to the beginning of file or to some other position, although I’d suggest to try to find way that wouldn’t require using seek().
Did this solution work for you? Because I tried all the possibilities. Can you try only for the superman thing and check if that is working or not.
My test code to check the superman string is below. Please modify and check if this works or not.
I’m not sure what is happening here. Why the original password to hash (hasher) is modified in the loop? With each loop pass it gets prepended and appended another salt, on top of previous. What is the relevance of if line != lines[-1]:?
lets assume: a,b,c,d,e are salts and ‘super’ is to be hashed.
then we loop through all salts and then
let hash = ‘super’
for i in salts:
hash = i+hash+i
for every time the loop executes.
//ahasha
//bahashab
//cbahashabc
//dcbahashabcd
…
I am not splitting each line of file using lines.split(’\n’)
I am using splitlines() function so I have to remove the last two characters i.e., \n from each line. But the last line doesn’t contain a \n so I have to use line!=lines[-1]
Using your example salts and super password, if salt is to be added both at the beginning and end, then hashed and checked should be following strings:
asupera
bsuperb
csuperc
dsuperd
esupere
However in project for every salt needs to be checked case with it prepended to the password and case with it appended to password.
\n is considered as a single character - you can check it i.e. with len('\n') - but in this example that’s not something to concern, as previously used splitlines() method removes new line characters. Additionally lines[-1] gets you last salt in the list, not last character of it.
Ohh… thank you for clarifying it…
I misunderstood the problem
And in the second case splitlines() will ignore ‘\n’. So every element of the for loop except the last one will have \n(as a character) at the end.
And yes it returns the last salt and not character it was a typo. My bad
I am not going to paste my final code here, but I’ve got it working now, passing all the tests.
For those who have encountered the same problem as I have, looking at the following Q&A should help without using seek(). If you want to search on your own, please ignore.