Python: 3 Ways to Hash a Password

Updated: May 25, 2023 By: Khue Post a comment

Overview

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.

Install:

pip install passlib

Example:

# 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))

Output:

Hashed: $5$uyIQZfZ//HGayL0H$wTEVtf1xMEPqb07/ohM6voheEwHbTFwpXp3ZSkQJ5h/
Verified: True

Using the hashlib module

The 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.

Install hashlib:

pip install hashlib

Example:

# 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.

Install:

pip install bcrypt

Example:

# 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):

Hashed: b'$2b$12$.G2vbFwfyr5MRUts6pa96OKegHnghfHTwH.cIo9AfP1Z6q4FvlUY6'

Conclusion

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!