This concise article shows you three different ways to hash a password in Python. Before seeing the code, let’s clarify some concepts and jargon. This part is boring with words, but it’s worth reading.
What is password hashing?
Hashing a password is the process of converting a plaintext password into a string of characters that looks like gibberish by using a cryptographic hash function. As long as you pass the same plaintext password to the hash function, you get exactly the same hashed string. However, it is almost impossible (and should be impossible) to convert the hashed string back to the provided password.
Salts in password hashing
In the context of password hashing, a salt is a random and unique value that is added to a password before it is hashed (even if two users have the same password, their salts will be different). The salt is then stored along with the hashed password in the database. When the user attempts to log in, the salt is retrieved from the database and combined with the entered password for hashing. The resulting hash is then compared with the stored hashed password for verification.
The primary purpose of using a salt is to defend against attacks that use precomputed tables of password hashes, such as rainbow table attacks. Rainbow tables are essentially large databases that contain precomputed hashes for a wide range of possible passwords. By using a salt, each password gets a unique hash, even if two users have the same password. This makes it impractical for attackers to create rainbow tables that cover all possible salts.
Why use password hashing?
Password hashing is important because it protects your users’ plaintext passwords. Even when your database is hacked, there is no way for the attacker to read and use your users’ original passwords. They only have meaningless hashes.
The boring part of this article ends here. Now, it’s time for the interesting one: code.
Three Ways to Hash a Password
Using the passlib module
This dude brings to the table a high-level interface for various hashing algorithms such as SHA-1, SHA-2, SHA-3, bcrypt, scrypt, and argon2.
passlib also supports salting, rounds, and other parameters for each algorithm. Passlib can also verify hashed passwords against plain passwords.
pip install passlib
# slingacademy.com # Hashing password using passlib from passlib.hash import sha256_crypt password = "secret" # the password to be hashed # hash the password using sha256_crypt with 5000 rounds and a random salt hashed = sha256_crypt.using(rounds=5000).hash(password) # print the hashed password print("Hashed:", hashed) # verify the hashed password against the plain password print("Verified:", sha256_crypt.verify(password, hashed))
Hashed: $5$uyIQZfZ//HGayL0H$wTEVtf1xMEPqb07/ohM6voheEwHbTFwpXp3ZSkQJ5h/ Verified: True
Using the hashlib module
hashlib module provides various hashing algorithms such as SHA-1, SHA-2, SHA-3, and BLAKE2. It also provides a function called
pbkdf2_hmac(), which implements the PBKDF2 (Password-Based Key Derivation Function 2) algorithm. PBKDF2 is a standard algorithm that applies a hashing function multiple times to the password and salt to make it harder for attackers to unveil it.
pip install hashlib
# slingacademy.com # password hashing example import hashlib import os import base64 # the password to be hashed password = b"secret" # a random salt salt = os.urandom(16) # the number of iterations to apply the hashing function iterations = 100000 # the length of the derived hashed_password in bytes dklen = 32 # hash the password using pbkdf2_hmac with SHA-256 algorithm hashed_password = hashlib.pbkdf2_hmac( "sha256", password, salt, iterations, dklen ) # encode the hashed_password and salt in base64 for storage hashed_password_b64 = base64.b64encode(hashed_password) salt_b64 = base64.b64encode(salt) # print the hashed_password and salt print("hashed_password:", hashed_password_b64) print("Salt:", salt_b64)
The output will look like this (it will change each time you re-run the code):
hashed_password: b'rVOSKrFn/TvP8xrnCUbBRxCcIW2rlfm1xtY9qwRPEs4=' Salt: b'lqHtG1AZQt4CLiVRSiMX3w=='
Using the bcrypt module
This module gives you a hashing algorithm based on the Blowfish cipher. Bcrypt is designed to be slow and adaptive, meaning that it can adjust the number of iterations based on the available computing power. Bcrypt also automatically generates and stores a salt for each password.
pip install bcrypt
# slingacademy.com # Hashing password using bcrypt import bcrypt password = b"secret" # the password to be hashed salt = bcrypt.gensalt() # generate a random salt # hash the password using bcrypt with 12 rounds of work factor hashed = bcrypt.hashpw(password, salt) # print the hashed password print("Hashed:", hashed)
My output (as always, your result will be different from mine due to the randomness):
You’ve learned three different approaches to hashing passwords in Python. All of them are secure, battle-test, and widely used in the software industry, including big enterprises. Choose the one that suits your needs and go with it. This tutorial ends here (as I promised, it’s very short and concise). Happy coding & enjoy your day!