Salt in PBKDF2 - Python
Asked Answered
E

1

7

I'm just learning about securing password while developing using MySQL and Python, following this tutorial.

It's my understanding that the userpassword is stored at the database hashed, and the salt is stored along side unencrypted, so that we can grab the hashed password and the salt, and rehash using the salt the inputted password, then compare the two.

Though, when using PBKDF2 (via the passlib.hash.sha256_crypt() function) I can't set my own salt, only its size. So how can I rehash the password using the same salt so I can compare both?

Excited answered 22/9, 2016 at 19:10 Comment(13)
hashlib.pbkdf2_hmac() takes a salt. What function are you using?Geophysics
Im using pbkdf2_sha256.encrypt, following the guide in cyberciti.biz/python-tutorials/…Excited
That implementation also takes a salt. When not specified, one is generated for you.Geophysics
Can I just do pbkdf2_sha256.encrypt(arg, arg, salt='blabla235') ?Excited
Note that the returned string contains the salt, so you don't need to generate one up front. The string is of the form $<type>$rounds=<rounds>$salt$hash, so if you want to store the hash separately you can if you want to.Geophysics
Yes, the documentation certainly states a salt argument is accepted. pbkdf2_sha256.encrypt("password", rounds=200000, salt='blabla235')Geophysics
"TypeError: salt must be bytes, not str"Excited
It would seem like salt is the same thing as salt_sizeExcited
So pass in bytes: b'blabla235'. No, salt_size determines how big a salt is generated for you. It is not the same thing as salt.Geophysics
that works, huh I guess simply converting was enough. Thanks a lot! Please reply with an answer so I can check it as rightExcited
Please edit your question first to make it clear what function and tutorial you were using. As it stands it doesn't meet our question requirements.Geophysics
Okay, should I send you a message once its corrected?Excited
That'd be helpful :-) I may not have time tonight but will do so then tomorrow morning.Geophysics
G
9

The Passlib Password Hash interface either lets you set the salt size, or the salt value itself. From the documentation on pbkdf2_sha256:

  • salt (bytes) Optional salt bytes. If specified, the length must be between 0-1024 bytes. If not specified, a 16 byte salt will be autogenerated (this is recommended).

  • salt_size (int) – Optional number of bytes to use when autogenerating new salts. Defaults to 16 bytes, but can be any value between 0 and 1024.

so you can set your own pre-generated salt:

>>> from passlib.hash import pbkdf2_sha256
>>> pbkdf2_sha256.hash("password", rounds=200000, salt=b'spamhameggs')
'$pbkdf2-sha256$200000$c3BhbWhhbWVnZ3M$WL9OLVcb3f7HqHeNT./kCJeunydLCi4JykzEuAdewcI'

However, note that the salt is part of the returned string. The string contains not only the resulting hash, but also the algorithm, the number of rounds used and the salt used, delimited by $. The salt is encoded with a modified form of base64. You can verify this by decoding the string c3BhbWhhbWVnZ3M again::

>>> from passlib.utils.binary import ab64_decode
>>> ab64_decode(b'c3BhbWhhbWVnZ3M')
b'spamhameggs'

See the Format & Algorithm section for the pbkdf2_sha256 docs.

So when you store the full string pbkdf2_sha256 in the database, everything to validate the string is right there in the value, including the salt. Leaving generating a random salt is best left to that library as it'll use a secure method to generate one.

You may want to read the Passlib tutorial on password hashing, which includes coverage of how to hash passwords when storing in the database, and how to verify them again (e.g. using pdkdf2_sha256.verify(password_user_entered, hash_stored_in_database)), which covers exactly this ground.

Geophysics answered 23/9, 2016 at 12:18 Comment(4)
How secure is passlib? Perhaps I'm a bid paranoid, but are there standard libraries that do that? Maintained by Python devs?Beefy
@Riya: it's a long-running, popular Open Source library to handle this task, and as far as I know, the defacto library for this in the Python ecosystem. I don't think you can get more 'standard' than this.Geophysics
@Riya: searching on GitHub I found ~40k mentions in requirements.txt, setup.cfg, pyproject.toml and Pipfile dependency files.Geophysics
@Riya: last but not least, it's the de-facto password hashing library for most Python web frameworks; e.g. the official FastAPI tutorial references it, and while Flask has several packages handling user logins, at least 3 of them use passlib for hashing (Flask-User, -Security and -Security-Too).Geophysics

© 2022 - 2024 — McMap. All rights reserved.