I have been looking through ths hashlib documentation but haven't found anything talking about using salt when hashing data.
Help would be great.
Samir's answer is correct but somewhat cryptic. Basically, the salt is just a randomly derived bit of data that you prefix or postfix your data with to dramatically increase the complexity of a dictionary attack on your hashed value. So given a salt s and data d you'd just do the following to generate a salted hash of the data:
import hashlib
hashlib.sha512( s + d ).hexdigest()
See this wikipedia article for more details
Just add the salt to your sensitive data:
>>> import hashlib
>>> m = hashlib.sha512()
>>> m.update('salt')
>>> m.update('sensitive data')
>>> m.hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
>>> n = hashlib.sha512()
>>> n.update('%ssensitive data' % 'salt')
>>> n.hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
>>> hashlib.sha512('salt' + 'sensitive data').hexdigest()
'70197a4d3a5cd29b62d4239007b1c5c3c0009d42d190308fd855fc459b107f40a03bd427cb6d87de18911f21ae9fdfc24dadb0163741559719669c7668d7d587'
Salting isn't a magical process that the library needs to help you with—it's just additional data provided to stop rainbow tables from working.
>>> import hashlib
>>> m = hashlib.sha512()
>>> m.update(b"Nobody inspects")
>>> m.update(b" the spammish repetition")
>>> m.digest()
b'\xd0\xf4\xc1LH\xadH7\x90^\xa7R\x0c\xc4\xafp\x0fd3\xce\t\x85\xe6\xbb\x87\xb6\xb4a|\xb9D\xab\xf8\x14\xbdS\x96M\xdb\xf5[A\xe5\x81+:\xfe\x90\x89\x0c\nM\xb7\\\xb0Cg\xe19\xfdb\xea\xb2\xe1'
>>> m.update(b"My super-secret salt.")
>>> m.digest()
b'\xcd\xd7K\xd9!~\xa8\x1d6\x9b\xa6\xde\x06\t\x02\xa1+}\xaeNA\x94a`\xaa\xf4\xe9\xb5\xff\x1f\x9cE\x84m\xbb\x98U\xb4z\x92\x9e\xe8\xc9\xc2\xc8\x8f\x068e\xb0\r\xed\xb7\xde\x80\xa6,\n\x111w{\xa2\x9b'
If you're looking for a replacement for crypt(), newer versions of glibc have SHA-512-based "$6$" with a variable iteration count (see Ulrich Drepper's page, which has a description and links to a complete C implementation of sha512_crypt_r()).
Writing your own crypto is highly unadvisable — the above sha512(salt+password) doesn't help against a brute-force attack.
For generating salt, use something like os.urandom(16) for random bytes or ''.join(map(lambda x:'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord(x)%64], os.urandom(16))) for random base64-alike chars (for use with crypt()-alikes).
(I say base64-alike it's not the same as the Base64 in PEM/MIME.)
use passlib, writing your own password crypto is an almost sure way to failure.
SHA512 isn't a great way to store hashed passwords these days. You should be using bcrypt or something similar. What's important is that salting is built in and that the algorithm has a significant work factor.
If you salt your SHA512 passwords by simply appending (or prepending) the salt to the plaintext, anyone who gets their hands on a set of your hashed passwords and applies a modern cracking tool (http://arstechnica.com/security/2013/05/how-crackers-make-minced-meat-out-of-your-passwords/) will be able to see the concatenated password+salt values and will probably, through trivial pattern matching, be able to separate the password portion from the salt portion for most if not all of the accounts in question.
I haven't thought this through all the way, and I am by no means a security expert, but it seems to me that if you were to encrypt (using, for example, AES256) the password using the salt as the key, and then hash that with SHA512, you'd be safe from the vulnerability I described above.
However, at that point you've put in more effort than it would have taken to switch to bcrypt and you still wouldn't have the protection of a work factor, so I would only recommend an approach like that if the environment you're working in does not offer that option.
yes yes if my password is "pass" and my salt is "word"
my pass+salt is "password" same as just use password xD
or we use very secure crypth that safe salt to hashed output lol.
we just strip salt and generate hash with random passwords when we got same hash we got password lol lol
Related
I'm hashing a password as follows:
mysalt = os.urandom(12).encode('hex')
passhash = mysalt + pw
hash = str(pbkdf2_sha256.encrypt(passhash))
How can I verify this password with user entry? The following:
hash3 = str(pbkdf2_sha256.encrypt(passhash))
...returns a completely different value.
Thanks in advance.
Make sure you use the same salt when you store the password as when you're checking it: passhash values with different salts will result in different hashes.
You could either use the same salt for every password (more convenient), use and store a different salt for every user (more secure), or a combination of both.
Edit: You didn't specify which library you were using to get pbkdf2_sha256. It could be that that library can handle salt-related tasks by itself. PassLib, for example, will generate a salt for you and include it in the result. It offers a verify method to check the user's input against that result.
Would advise against comparing the resulting strings - often encoding gets in the way. Try comparing the actual bytes.
the solution is:
import os
from passlib.hash import pbkdf2_sha256
mysalt=os.urandom(12).encode('hex')
hash = pbkdf2_sha256.encrypt("password")
print hash
print pbkdf2_sha256.verify("password", hash)
pwd='sefrhiloliutzrthgrfsdyv<sef234244567!"234wsdycvhn'
mypass =mysalt+pwd
print mypass
hash2 =pbkdf2_sha256.encrypt(mypass, rounds =200000)
hash1= pbkdf2_sha256.encrypt(pwd, rounds=80000, salt_size=100)
print"hash2: ", hash2
print pbkdf2_sha256.verify(mypass,hash2)
After reading here a bit about salting passwords, it seems that it's best to use a unique salt for each user. I'm working on implementing Flask-Security atm, and from the documentation it appears you can only set a global salt: ie SECURITY_PASSWORD_SALT = 'thesalt'
Question: How would one go about making a unique salt for each password?
Thanks!
edit: from the docs on Flask-Security, I found this, which seems to again suggest that this module only uses a single salt for all passwords out of the box.
flask_security.utils.get_hmac(password)
Returns a Base64 encoded HMAC+SHA512 of the password signed with the salt
specified by SECURITY_PASSWORD_SALT.
Yes, Flask-Security does use per-user salts by design if using bcrypt (and other schemes such as des_crypt, pbkdf2_sha256, pbkdf2_sha512, sha256_crypt, sha512_crypt).
The config for 'SECURITY_PASSWORD_SALT' is only used for HMAC encryption. If you are using bcrypt as the hashing algorithm Flask-Security uses passlib for hashing and it generates a random salt during hashing. This confustion is noted in issue 268: https://github.com/mattupstate/flask-security/issues/268
It can be verified in the code, walking from encrypt to passlib:
flask_security/utils.py (lines 143-151, 39, and 269)
def encrypt_password(password):
...
return _pwd_context.encrypt(signed)
_pwd_context = LocalProxy(lambda: _security.pwd_context)
flask_security/core.py (269, 244-251, and 18)
pwd_context=_get_pwd_context(app)
def _get_pwd_context(app):
...
return CryptContext(schemes=schemes, default=pw_hash, deprecated=deprecated)
from passlib.context import CryptContext
and finally from: https://pythonhosted.org/passlib/password_hash_api.html#passlib.ifc.PasswordHash.encrypt
note that each call to encrypt() generates a new salt,
Turns out that if you use bcrypt, it takes care of the salting and stores it with the hash. So I'll go that route!
Thanks to this topic which lead me to this discovery:
Do I need to store the salt with bcrypt?
So I've recently learned how to store passwords in a DB, that is by adding a salt to the plaintext password, hashing it, and then storing the hash.
I'm working on a really small Flask app to try all this out, but I'm having a problem with the password hashing and checking parts of the process. It seems that I"m ending up with two different hashes for the same input and I can't seem to figure out why.
I ran a little experiment in the interpreter to test things out.
>>> from os import urandom
>>> salt = urandom(32).encode('base-64')
>>> salt
'+3DejJpQZO9d8campsxOB6fam6lBE0mJ/+UvFf3oG8c=\n'
>>> plaintext_pw = 'archer'
>>> plaintext_pw
'archer'
>>> salted_pw = plaintext_pw + salt
>>> salted_pw
'archer+3DejJpQZO9d8campsxOB6fam6lBE0mJ/+UvFf3oG8c=\n'
>>> from flaskext.bcrypt import Bcrypt
>>> bc = Bcrypt(None)
>>> hashed_pw = bc.generate_password_hash(salted_pw)
>>> hashed_pw
'$2a$12$znMwqAw.GliVE8XFgMIiA.aEGU9iEZzZZWfxej5wSUFP0huyzdUfe'
All is working well at this point, but when I turn around and do this:
>>> bc.generate_password_hash(plaintext_pw + salt)
'$2a$12$qbywkEjuJgmBvXW6peHzAe.rWjoc.ybFKRNzuZhom2yJSXaMRcVTq'
I get a completely different hash, even though I started with the same plaintext_pw and salt. I thought that wasn't supposed to happen? Furthermore each subsequent call to bc.generate_password_hash() gives me different results each time:
>>> bc.generate_password_hash(plaintext_pw + salt)
'$2a$12$FAh9r4oaD40mWPtkClAnIOisP37eAT5m.i.EGV1zRAsPNbxg3BlX2'
>>> bc.generate_password_hash(plaintext_pw + salt)
'$2a$12$gluk9RUiR6D0e2p1J.hNgeE3iTFxDUlCNvFJOsCZZk89ngO.Z6/B6'
As far as I can tell plaintext_pw and salt aren't changing between calls. I can't seem to spot the error here, could someone explain to me exactly what's happening here, and what it is I'm doing wrong?
Ok so it looks like I've solved my problem. Turns out I wasn't using bcrypt properly. Here's what I learned:
The hashes were different each time I called generate_password_hash because bcrypt automatically generates a salt for you and appends it to the hashed password, so no need to generate it with urandom or store it separately.
I didn't talk about this in my post, but its worth noting here anyway - I assumed that on login you would need to call generate_password_hash() and provide the password from the login form to create a second hash for check_password_hash() to compare against, but that isn't necessary. check_password_hash() can be called with the stored hash and the form password (respectively) and it will automatically take care of salting and hashing the form password, and comparing it to the stored hash.
And with that everything is working fine now. Hope this helps someone else!
I want to be able to generate and re-generate the same RSA keys from a password (and salt) alone in python.
Currently I was doing it using pycrypto, however, it does not seem to generate the same exact keys from the password alone. The reason seems to be that when pycrypto generates a RSA key it uses some sort of random number internally.
Currently my code looks as follows:
import DarkCloudCryptoLib as dcCryptoLib #some costume library for crypto
from Crypto.PublicKey import RSA
password = "password"
new_key1 = RSA.generate(1024) #rsaObj
exportedKey1 = new_key1.exportKey('DER', password, pkcs=1)
key1 = RSA.importKey(exportedKey1)
new_key2 = RSA.generate(1024) #rsaObj
exportedKey2 = new_key2.exportKey('DER', password, pkcs=1)
key2 = RSA.importKey(exportedKey2)
print dcCryptoLib.equalRSAKeys(key1, key2) #wish to return True but it doesn't
I don't really care if I have to not use pycrypto, as long as I can generate these RSA keys from passwords and salts alone.
Thanks for the help in advance.
Just for reference, this is how dcCryptoLib.equalRSAKeys(key1, key2) function looks like:
def equalRSAKeys(rsaKey1, rsaKey2):
public_key = rsaKey1.publickey().exportKey("DER")
private_key = rsaKey1.exportKey("DER")
pub_new_key = rsaKey2.publickey().exportKey("DER")
pri_new_key = rsaKey2.exportKey("DER")
boolprivate = (private_key == pri_new_key)
boolpublic = (public_key == pub_new_key)
return (boolprivate and boolpublic)
NOTE: Also, I am only using RSA for authentication. So any solution that provides a way of generating secure asymmetric signatures/verifying generated from passwords are acceptable solutions for my application. Though, generating RSA keys from passwords I feel, is a question that should also be answered as it seems useful if used correctly.
If you're trying to implement an authenticated encryption scheme using a shared password, you don't really need an RSA key: all you need is an AES key for encryption and an HMAC key for authentication.
If you do need to generate an asymmetric signature than can be verified without knowing the password, you're going to have to somehow generate RSA (or DSA, etc.) keys in a deterministic manner based on the password. Based on the documentation, this should be possible by defining a custom randfunc, something like this:
from Crypto.Protocol.KDF import PBKDF2
from Crypto.PublicKey import RSA
password = "swordfish" # for testing
salt = "yourAppName" # replace with random salt if you can store one
master_key = PBKDF2(password, salt, count=10000) # bigger count = better
def my_rand(n):
# kluge: use PBKDF2 with count=1 and incrementing salt as deterministic PRNG
my_rand.counter += 1
return PBKDF2(master_key, "my_rand:%d" % my_rand.counter, dkLen=n, count=1)
my_rand.counter = 0
RSA_key = RSA.generate(2048, randfunc=my_rand)
I've tested this, and it does generate deterministic RSA keys (as long as you remember to reset the counter, at least). However, note that this is not 100% future-proof: the generated keys might change, if the pycrypto RSA key generation algorithm is changed in some way.
In either case, you'll almost certainly want to preprocess your password using a slow key-stretching KDF such as PBKDF2, with an iteration count as high as you can reasonably tolerate. This makes breaking your system by brute-force password guessing considerably less easy. (Of course, you still need to use strong passwords; no amount of key-stretching is going to help if your password is abc123.)
Pass "randfunc" to the RSA.generate, and randfunc should return the output bytes, in order, of a well-known key derivation function that has been configured with enough output bits for RSA to "always complete" without needing more bits.
Argon2, scrypt, PBKDF2 are examples of KDFs designed for this purpose.
It may be possible to use Keccak directly as a KDF by specifying a high number of output bits.
If your generation function follows a well known standard closely, it should work across multiple implementations.
I am looking to generate passwords using strings typed by the user, the book I am reading recommends using sha over md5 because it is considered stronger.
sha however has been deprecated and I am now using the hashlib module to encrypt me strings in a similar way to that shown here: http://docs.python.org/py3k/library/hashlib.html#module-hashlib.
import os
import hashlib
from getpass import getpass
print('Username: ' + os.environ['USER'])
passwd = getpass('Password: ')
h = hashlib.md5()
h.update(passwd.encode())
passwd_encrypt = h.hexdigest()
I am then comparing passwd_encrypt with a plain ascii file containing a list of usernames and encrypted passwords like so:
THO 5f4dcc3b5aa765d61d8327deb882cf99
Is this a suitable technique for encryption of the password or is there a better way? I am also interested in whether storing the passwords in this way is suitable and what the alternatives may be.
Thank you
There is no "sha" algorithm. The sha1 algorithm is much stronger than md5, since md5 is completely broken. I believe there is an algorithm that takes microseconds to generate a collision.
Sha1 has been considerably weakened by cryptanalysts, and the search is on for the next big thing, but it is still currently suitable for all but the most paranoid.
With regard to their use in passwords, the purpose is to prevent discovery of the original password. So it doesn't really matter much that md5 collisions are trivial to generate, since a collision simply yields an alternate password that has the same md5 hash as the original password, it doesn't reveal the original password.
Important note:
Your version is missing an important component: the salt. This is a random string that is concatenated to the original password in order to generate the hash, and then concatenated to the hash itself for storage. The purpose is to ensure that users with the same password don't end up with the same stored hash.
import random
print('Username: ' + os.environ['USER'])
passwd = getpass('Password: ')
salt = ''.join(random.choice('BCDFGHJKLMNPQRSTVWXYZ') for range(4))
h = hashlib.md5()
h.update(salt)
h.update(passwd.encode())
passwd_encrypt = salt + h.hexdigest()
You then verify the password by reusing the stored salt:
passwd = getpass('Password: ')
salt = passwd_encrypt[:4]
h = hashlib.md5()
h.update(salt)
h.update(passwd.encode())
if passwd_encrypt != salt + h.hexdigest():
raise LoginFailed()
Comparing the hash of the password with a saved hash is a suitable method for authentication.