This code is supposed to hash a password with a salt. The salt and hashed password are being saved in the database. The password itself is not.
Given the sensitive nature of the operation, I wanted to make sure everything was kosher.
import hashlib
import base64
import uuid
password = 'test_password'
salt = base64.urlsafe_b64encode(uuid.uuid4().bytes)
t_sha = hashlib.sha512()
t_sha.update(password+salt)
hashed_password = base64.urlsafe_b64encode(t_sha.digest())
This question is related to
python
authentication
hash
passwords
salt
For this to work in Python 3 you'll need to UTF-8 encode for example:
hashed_password = hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
Otherwise you'll get:
Traceback (most recent call last):
File "", line 1, in
hashed_password = hashlib.sha512(password + salt).hexdigest()
TypeError: Unicode-objects must be encoded before hashing
Firstly import:-
import hashlib, uuid
Then change your code according to this in your method:
uname = request.form["uname"]
pwd=request.form["pwd"]
salt = hashlib.md5(pwd.encode())
Then pass this salt and uname in your database sql query, below login is a table name:
sql = "insert into login values ('"+uname+"','"+email+"','"+salt.hexdigest()+"')"
Here's my proposition:
for i in range(len(rserver.keys())):
salt = uuid.uuid4().hex
print(salt)
mdp_hash = rserver.get(rserver.keys()[i])
rserver.set(rserver.keys()[i], hashlib.sha256(salt.encode() + mdp_hash.encode()).hexdigest() + salt)
rsalt.set(rserver.keys()[i], salt)
passlib seems to be useful if you need to use hashes stored by an existing system. If you have control of the format, use a modern hash like bcrypt or scrypt. At this time, bcrypt seems to be much easier to use from python.
passlib supports bcrypt, and it recommends installing py-bcrypt as a backend: http://pythonhosted.org/passlib/lib/passlib.hash.bcrypt.html
You could also use py-bcrypt directly if you don't want to install passlib. The readme has examples of basic use.
see also: How to use scrypt to generate hash for password and salt in Python
The smart thing is not to write the crypto yourself but to use something like passlib: https://bitbucket.org/ecollins/passlib/wiki/Home
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. Therefor I think it is better to use a package written by someone else who is knowledgable 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.
I don' want to resurrect an old thread, but... anyone who wants to use a modern up to date secure solution, use argon2.
https://pypi.python.org/pypi/argon2_cffi
It won the the password hashing competition. ( https://password-hashing.net/ ) It is easier to use than bcrypt, and it is more secure than bcrypt.
As of Python 3.4, the hashlib
module in the standard library contains key derivation functions which are "designed for secure password hashing".
So use one of those, like hashlib.pbkdf2_hmac
, with a salt generated using os.urandom
:
from typing import Tuple
import os
import hashlib
import hmac
def hash_new_password(password: str) -> Tuple[bytes, bytes]:
"""
Hash the provided password with a randomly-generated salt and return the
salt and hash to store in the database.
"""
salt = os.urandom(16)
pw_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
return salt, pw_hash
def is_correct_password(salt: bytes, pw_hash: bytes, password: str) -> bool:
"""
Given a previously-stored salt and hash, and a password provided by a user
trying to log in, check whether the password is correct.
"""
return hmac.compare_digest(
pw_hash,
hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
)
# Example usage:
salt, pw_hash = hash_new_password('correct horse battery staple')
assert is_correct_password(salt, pw_hash, 'correct horse battery staple')
assert not is_correct_password(salt, pw_hash, 'Tr0ub4dor&3')
assert not is_correct_password(salt, pw_hash, 'rosebud')
Note that:
os.urandom
always uses a cryptographically secure source of randomnesshmac.compare_digest
, used in is_correct_password
, is basically just the ==
operator for strings but without the ability to short-circuit, which makes it immune to timing attacks. That probably doesn't really provide any extra security value, but it doesn't hurt, either, so I've gone ahead and used it.For theory on what makes a good password hash and a list of other functions appropriate for hashing passwords with, see https://security.stackexchange.com/q/211/29805.
Based on the other answers to this question, I've implemented a new approach using 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.
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)
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
Source: Stackoverflow.com