SHA-1 Password Cracker - function with salt not working

Tell us what’s happening:

I am implementing the one with salt.

I am not sure what the instruction means by

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
            ... code for without salt ...


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.

Challenge: SHA-1 Password Cracker

Link to the challenge:

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.

Hi, sanity.

Thanks for your help.

I thought I got it but still not working.

I understand that there are two possibilities of how salt is used for creating a hash:

  1. salt + plain_password, and
  2. 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.

import hashlib

def crack_sha1_hash(hasher):

    hasher1 = hasher

    hasher2 = hasher

    with open('known-salts.txt', 'r') as f:

        lines =

        for line in lines:

            if line != lines[-1]:

                hasher = line[:-2]+hasher+line[:-2]

                hasher1 = line[:-2]+hasher

                hasher2 = hasher+line[:-2]


                hasher = line+hasher+line

                hasher1 = line+hasher

                hasher2 = hasher+line


    m = hashlib.sha1(bytes(hasher, 'utf-8')).hexdigest()


    print(hashlib.sha1(bytes(hasher1, 'utf-8')).hexdigest())

    print(hashlib.sha1(bytes(hasher2, 'utf-8')).hexdigest())


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]:?

1 Like

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.

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:


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 :smiley:
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 :smiley:

So basically it worked. I got one possibility which has worked in this scenario.

 known-salts.txt should be appended AND prepended to each password from top-10000-passwords.txt

This sentence is very confusing and fcc needs to change this one :smiley:.

Solved the problem finally. Thanks to @sanity or else I would have gone stuck here for a long time. :smiley:

1 Like

Thank you so much for your help, sanity. :smile:

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.