40

I would like to use bcrypt to hash passwords and later verify if a supplied password is correct.

Hashing passwords is easy:

import bcrypt

password = u'foobar'
password_hashed = bcrypt.hashpw(password, bcrypt.gensalt())

# then store password_hashed in a database

How can I compare a plain text password to the stored hash?

tom
  • 21,844
  • 6
  • 43
  • 36
MFB
  • 19,017
  • 27
  • 72
  • 118

6 Answers6

71

With py-bcrypt, you don't need to store the salt separately: bcrypt stores the salt in the hash.

You can simply use the hash as a salt, and the salt is stored in the beginning of the hash.

>>> import bcrypt
>>> salt = bcrypt.gensalt()
>>> hashed = bcrypt.hashpw('secret', salt)
>>> hashed.find(salt)
0
>>> hashed == bcrypt.hashpw('secret', hashed)
True
>>>
ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
user1581840
  • 726
  • 6
  • 2
  • 8
    Great answer, but just an FYI that `hash` is a Python 2 and 3 reserved keyword (builtin func), and setting `hash = ...` overrides the builtin in whatever scope you're in. I would change that to something like `hashed` or `pw_hash`, etc. – alichaudry Mar 29 '17 at 20:21
  • 1
    I agree. This `hash` must be substituted by some other name :). – ivanleoncz Oct 02 '17 at 21:09
  • 9
    Don't forget to encode your string, `'secret'.encode()`. Note: tested in Python 3. – Yamaneko Feb 04 '18 at 03:15
19

The documentation doesn't mention storing the salt, it says you just have to:

#Initial generation
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
#Store hashed in your db

#Load hashed from the db and check the provided password
if bcrypt.hashpw(password, hashed) == hashed:
    print "It matches"
else:
    print "It does not match"

http://www.mindrot.org/projects/py-bcrypt/

  • A new salt is generated each time you call bcrypt.gensalt(), therefore you must save the salt along with the result of bcrypt.hashpw(). – skyler Sep 03 '12 at 22:23
  • 10
    @skyler - with bcrypt, the salt is stored as part of the hash. it's saved into the hash , and the hash is compared against it automatically. – Jonathan Vanasco Oct 22 '12 at 00:31
  • 5
    Comparing hashes with `==` introduces a security issue (timing attacks). You should use `hmac.compare_digest`. – rubik Feb 26 '20 at 15:42
6

I'm not familiar with Python but I think you can use:
public static boolean checkpw(java.lang.String plaintext, java.lang.String hashed)

# Check that an unencrypted password matches one that has  
# previously been hashed.
if bcrypt.checkpw(plaintext, hashed):
    print "It matches"
else:
    print "It does not match"
Zen
  • 23
  • 5
Govind Singh
  • 15,282
  • 14
  • 72
  • 106
  • +1 for `checkpw()` but do not forget to use `encode('utf-8')` or any encoding that you used while hashing on the plain text before either generating or checking a password – SATYAJEET RANJAN May 16 '19 at 20:55
6

Later, let's say you have an user-input password user_pass. You'd hash that as well, and then compare the hash with the stored hash, and if they match, then the original passwords also matched.

Note that bcrypt automatically stores the salt value as part of the hashed password, so that you can use it when you hash the future input as well.

First time around:

import bcrypt

password = u'foobar'
salt = bcrypt.gensalt()
password_hashed = bcrypt.hashpw(password, salt)

# store 'password_hashed' in a database of your choosing

Later times:

import bcrypt
password = something_that_gets_input()

stored_hash = something_that_gets_this_from_the_db()

if bcrypt.hashpw(password, stored_hash) == stored_hash:
    # password matches
Amber
  • 507,862
  • 82
  • 626
  • 550
  • Thank you.. being new to this, I was completely missing the fact that the salt and the password need to be stored and subsequently compared. Thanks heaps! – MFB Mar 04 '12 at 22:56
  • 3
    There is no need to store salt when using bcrypt. The answer below is the right one. – Sharoon Thomas May 01 '13 at 02:27
0

I think this one will work better:

for i in range(len(rserver.keys())):
    salt = bcrypt.gensalt(12)
    
    mdp_hash = rserver.get(rserver.keys()[i])
    rserver.set(rserver.keys()[i], bcrypt.hashpw(mdp_hash.encode(),bcrypt.gensalt(12) ))

    rsalt.set(rserver.keys()[i], salt)
StarGit
  • 35
  • 14
0

First retrieve the hashed password from the database.

hashed_pwd = ...
plain_text_pwd = 'my_password'
pwdbytes = plain_text_password.encode('utf-8)

assuming your password is stored in text format in your db,compare them like so:

if bcrypt.hashpw(pwdbytes, hashed_pwd.encode('utf-8')).decode('UTF-8') == hashed_pwd:
                print('Login successfull')

if it is stored in bytes(blob) compare like so:

if bcrypt.hashpw(pwdbytes, hashed_pwd) == hashed_pwd:
                    print('Login successfull')
Prateek p
  • 117
  • 1
  • 11