What is `$6$rounds=` when running Passlib with Python? - python

I'm generating SHA-512 encoded password keys with Python's Passlib's command.
python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_crypt.encrypt(getpass.getpass())"
This is per Ansible documentation: http://docs.ansible.com/ansible/faq.html#how-do-i-generate-crypted-passwords-for-the-user-module).
It prompts for a password, which I input. And then it returns the key.
Regardless of the password I input, all keys created begin with $6$rounds=...
What does this mean? Is this part of the key?

This indicates to the schema for the used algorithm. In the case of sha512_crypt 6 indicates sha512 and rounds=x indicate the number of rounds to compute the hash.
Also current NIST standards suggest pbkdf2_sha256 for password hashing.

Related

recreating pythons werkzeug.security generate_password_hash in C#

Seems simple enough, and there are plenty of examples but I just can't seem to get hashes that verify with werkzeug.security's check_password_hash in python.
private string Generate_Passwd_Hash()
{
string _password = "Password";
string _salt = "cXoZSGKkuGWIbVdr";
SHA256 MyHash = SHA256.Create();
byte[] hashable = System.Text.Encoding.UTF8.GetBytes(_salt + _password);
byte[] resulthash = MyHash.ComputeHash(hashable);
return "sha256$" + _salt + "$" + BitConverter.ToString(resulthash).Replace("-", "").ToLower();
}
this should generate;
sha256$cXoZSGKkuGWIbVdr$7f5d63e849f0a2c0c5c2bd6ae4e45ead2ac730c853a1ed3460e227c06c567f49
but doesn't.
EDIT
Reading through the python code for generate_password_hash and it has a default number of iterations of 260000. Which is probably what I'm missing.
I never used werkzeug but I tried to reproduce your probelem.
I had read the docs of werkzeug.security.generate_password_hash and realized it is used in password validation only, and not meant to be a universal hashing algorithm.
The document clearly says
Hash a password with the given method and salt with a string of the
given length. The format of the string returned includes the method
that was used so that check_password_hash() can check the hash.
hashlib.pbkdf2_hmac is the hashing algorithm werkzeug uses internally(from now on we call it underlying algorithm). and you don't need install it because it is in standard library.
The source code of check_password_hash shows it generates a random salt before calling underlying algorithm. The salt is to protect from attacks. And it is remembered by the werkzeug framework so that check_password_hash can use to validate later.
So to summarize:
werkzeug.security.generate_password_hash only guarantee that generated hash can be validated by check_password_hash, and no more. You simply cannot(or not supposed to) try to generate same hash by other libraries or languages.
If you really want to compare the hashing algorithm in python and C#, please post another question(or update this question) that compares underlying algorithm(hashlib.pbkdf2_hmac which allow specifying salt as parameter) with C# version. Note seems in C# there's no built in algorithm for pbkdf2, see Hash Password in C#? Bcrypt/PBKDF2.

How does password checking in bcrypt work?

So, I found the following example in bcrypt docs:
password = b"super secret password"
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
if bcrypt.checkpw(password, hashed):
print("It Matches!")
else:
print("It Does not Match :(")
And it seems to work. But I don't understand how. Shouldn't we use salt to generate a hash for checking?
I mean, we generated salt once and didn't save it in a variable. But then we want to compare the hash and the password with the function checkpw, but how does it know which salt to use to generate a hash for comparison?
The generated "hash" also contains the salt. It is in the Modular Crypt Format, documented here (thanks #Masklinn)
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
|<--- salt --->||<---- confirmation hash ---->|
The "2a" part gives information on the modular hash being used, "10" is the logarithmic cost parameter (i.e. the algorithm is to be iterated 210 times).
So, to verify that a password matches, you'll restart the bcrypt using the decoding of N9qo8uLOickgx2ZMRZoMye as a salt.
The salt gets saved in the hash itself. The scheme for bcrypt looks like the following:
$<used_algorithm>$<cost_factor>$<generated_salt><hash>$

Verify a hashed password

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)

Unique Salt per User using Flask-Security

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?

Generating passwords in Python 3.1.1

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.

Categories