Salt and hash a password in Python
Edit:
The library suggested in this answer is now outdated, and the hashlib key derivation functionality mentioned in this answer: https://stackoverflow.com/a/56915300/893857 is a good suggestion to use nowadays.
Original Answer The smart thing is not to write the crypto yourself but to use something like passlib: https://passlib.readthedocs.io/en/stable/#
It is easy to mess up writing your crypto code in a secure way. The nasty thing is that with non crypto code you often immediately notice it when it is not working since your program crashes. While with crypto code you often only find out after it is to late and your data has been compromised. Therefore I think it is better to use a package written by someone else who is knowledgeable about the subject and which is based on battle tested protocols.
Also passlib has some nice features which make it easy to use and also easy to upgrade to a newer password hashing protocol if an old protocol turns out to be broken.
Also just a single round of sha512 is more vulnerable to dictionary attacks. sha512 is designed to be fast and this is actually a bad thing when trying to store passwords securely. Other people have thought long and hard about all this sort issues so you better take advantage of this.
Based on the other answers to this question, I've implemented a new approach using bcrypt.
Why use bcrypt
If I understand correctly, the argument to use bcrypt
over SHA512
is that bcrypt
is designed to be slow. bcrypt
also has an option to adjust how slow you want it to be when generating the hashed password for the first time:
# The '12' is the number that dictates the 'slowness'
bcrypt.hashpw(password, bcrypt.gensalt( 12 ))
Slow is desirable because if a malicious party gets their hands on the table containing hashed passwords, then it is much more difficult to brute force them.
Implementation
def get_hashed_password(plain_text_password):
# Hash a password for the first time
# (Using bcrypt, the salt is saved into the hash itself)
return bcrypt.hashpw(plain_text_password, bcrypt.gensalt())
def check_password(plain_text_password, hashed_password):
# Check hashed password. Using bcrypt, the salt is saved into the hash itself
return bcrypt.checkpw(plain_text_password, hashed_password)
Notes
I was able to install the library pretty easily in a linux system using:
pip install py-bcrypt
However, I had more trouble installing it on my windows systems. It appears to need a patch. See this Stack Overflow question: py-bcrypt installing on win 7 64bit python
EDIT: This answer is wrong. A single iteration of SHA512 is fast, which makes it inappropriate for use as a password hashing function. Use one of the other answers here instead.
Looks fine by me. However, I'm pretty sure you don't actually need base64. You could just do this:
import hashlib, uuid
salt = uuid.uuid4().hex
hashed_password = hashlib.sha512(password + salt).hexdigest()
If it doesn't create difficulties, you can get slightly more efficient storage in your database by storing the salt and hashed password as raw bytes rather than hex strings. To do so, replace hex
with bytes
and hexdigest
with digest
.