The bcrypt hash value consists of the following parts:
$2b
— this indicates that the hash is generated according to the OpenBSD implementation of bcrypt.
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.
kn7yEh2nYiDqDYNY.hjiZO
— This is the 128-bit salt value, encoded in base64 as 22 ASCII characters
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)
$
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$