I have a bcrypt hash: $2b$10$kn7yEh2nYiDqDYNY.hjiZOtASBKT9uO4KozbFWDW2XLYnW58nkpq and a list with given plaintext passwords. How can I get the password from the list?

Is $2b$10$kn7yEh2nYiDqDYNY the salt?


for word in words:
    hash = bcrypt.hashpw(word.encode('UTF-8'), SALT)
    if TOMATCH == hash:

However, with this I get ValueError: Invalid salt. What am I doing wrong here?

  • $\begingroup$ With bcrypt.gensalt() you generate a complete new salt so the hash would never match with the tomatching hash we got? $\endgroup$
    – tanngo
    Feb 10, 2021 at 15:41
  • $\begingroup$ $ are separator characters, 2b is the algorithm designation, 10 is the work factor and I presume then that the characters between the $ and the dot are the base 64 encoded 96 bit salt (?), or it is included in the hash value and the dot is part of the base 64 encoding. $\endgroup$
    – Maarten Bodewes
    Feb 10, 2021 at 15:45

2 Answers 2


The bcrypt hash value consists of the following parts:

  1. $2b — this indicates that the hash is generated according to the OpenBSD implementation of bcrypt.

  2. 10$ — this is the "cost" parameter, indicating that the password is hashed with 210 (i.e. 1024) iterations of the blowfish cipher. A higher cost parameter results in password hashes that are harder to crack by brute force.

  3. kn7yEh2nYiDqDYNY.hjiZO — This is the 128-bit salt value, encoded in base64 as 22 ASCII characters

  4. The remaining characters correspond to the 184-bit blowfish hash value, encoded in base64 as 31 characters.

If you check the length of your string, I think you'll find that it's actually one character short, which would explain why you're getting error messages. If this character is simply missing, you could always try appending every possible character from 0-9, A-Z, a-z, . and /. One of them ought to work.

Incidentally, I think it would make more sense to use the checkpw() function in the bcrypt module instead of trying to extract the salt yourself. Here's some code that can check every possible last character. It will take a long time to run if the word list is large.

def check_partial_hash(h, words):
    import string
    for last_char in list(string.digits + string.ascii_letters + '/.'):
        hash = h + last_char
        for word in words:
            if bcrypt.checkpw(word.encode('UTF-8'), hash.encode('UTF-8')):
                return (word, hash)
    return None

partial_hash = u'$2b$10$kn7yEh2nYiDqDYNY.hjiZOtASBKT9uO4KozbFWDW2XLYnW58nkpq'
word_list = [ u'foo', u'bar', u'asd', u'baz' ]
check_partial_hash(partial_hash, word_list)

if you know the plaintext and hash password, then you can try below..for ex.

  • your password is 'code3' and it is hashed with SALT generate by bcrypt.gensalt()

  • hash_word=bcrypt.hashpw(word.encode('utf-8'),bcrypt.gensalt())

  • hash_word = b'$2b$12$C3reFNd9UBYHeb3/2ZbBk.yQ1cDowSulDHQIkWymx.WdoJ72yHKeu'

  • because salt is in the hash_word , while testing you can give

  • check_passwd =bcrypt.hashpw(word.encode('utf-8'),hash_word) and check password will be same as hash_word if your plaintext matches.

    check_passwd = b'$2b$12$C3reFNd9UBYHeb3/2ZbBk.yQ1cDowSulDHQIkWymx.WdoJ72yHKeu'

  • 1
    $\begingroup$ This should work indeed only when the salt is generated with bcrypt.gensalt. Ive tried to match the hashes this way, however nothing came out of it... $\endgroup$
    – tanngo
    Feb 10, 2021 at 16:25
  • $\begingroup$ but you have hash password and list of password. if you use above method, what is the error you get? can you provide the clear password list. I'll try. bcrypt.hashpw('code3'.encode('utf-8'),TOMATCH.encode('utf-8')) $\endgroup$
    – SSA
    Feb 11, 2021 at 4:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.