How Bcrypt Uses Salt for Password Protection
What is Bcrypt?
Bcrypt is a very popular npm library that is used to hash plain text passwords into hashes and compare the hashed password to the original password for authentication. But have you ever wondered how it works under the hood?
What does Bcrypt provide?
Bcrypt provides two main functionalities:
Hashing the password and converting it into a hash (a fixed-length string generated from the password using a hashing algorithm).
Comparing the generated hash with the plain-text password during authentication.
In this blog, we are going to understand how the salt works in the bcrypt compare function as it can be quite confusing about how will it help to secure the password. Why? We will see that together.
The hash function
When bcrypt hashes a password, it uses salt, a random value added to the password before hashing. This ensures that even if two users have the same password, their resulting hashes will be different. The simplest way to generate a hash is to use bcrypt’s built-in function that automatically generates the salt for you.
const hashedPassword = await bcrypt.hash(password, saltRounds)
In this example, saltRounds
is an integer that determines the number of times the hashing algorithm is applied. The more rounds, the stronger the hash, but at the cost of additional computation. Typically, saltRounds
values between 10-12 are common.
The Compare function
The compare
function in bcrypt is used to check if a provided plain-text password matches the hashed password stored in the database. It returns a boolean value: true
if the passwords match, and false
if they do not.
Now let's try running a code:
const bcrypt = require("bcrypt")
const pass = "thisismypass"
bcrypt.hash(pass, 10).then((hash) => {
console.log("generated hash =>",hash)
bcrypt.compare(pass, hash).then((success) => {
console.log("This is the result for comparison =>", success)
})
})
Now let’s look at the output that it generated:
Let’s analyze the output generated by the code above:
You might notice that even though we are running the same code twice with the same password, we get different hashed passwords. You might also wonder: “Shouldn’t the last characters of the generated hash be the same for the same password?” But they aren’t. Why is that?
This is where the concept of salt comes into play.
What is Salt?
Salt is nothing but a string that is used to add more randomness to the generated hash. It can be either some information about the user or some randomly generated string.
Now, you might have a question: “We’re not providing the salt explicitly in either of the bcrypt functions (the saltRounds
parameter is something different). So, how does bcrypt add the salt and verify the password without knowing the salt?"
When better understand this we first need to understand the structure/format of the generated hash.
$2b$10$<22-chracter salt><password hash>
The hash is divided into three major parts. You might have noticed that both of the hashes we generated earlier always start with $2b$10$
. Here's what these parts mean:
$2b: This represents the bcrypt algorithm version.
$10: This is the salt rounds (also known as the work factor). This tells bcrypt how many times to hash the password. The higher the value, the more computationally expensive the hashing process becomes.
<22-character salt>: This is the randomly generated salt, which is 22 characters long.
<password hash>: This is the actual hashed password generated using the password and salt.
But you might think that we can just separate the salt and the password hash, so how is it even protected?
This is where the concept of salt rounds comes into play. The salt rounds add extra layers of security by hashing the password repeatedly. The hashing is done 2^(saltRound) times. This also makes the function expensive thus more time is taken to prevent brute force attacks where attackers try multiple password combinations to guess the correct one.
Let’s Break It Down with an Example
Let’s take the password “thisismypass” and a randomly generated salt “thisisrandomgeneratedsalt”. Here’s how bcrypt would work:
First Step: Bcrypt combines the password and salt, and generates a hash. This is done once.
Second Step: The hash generated in step 1 is then used as input again and hashed, repeating the process 2^(saltRounds) times. So, if we set the salt rounds to 10, bcrypt will perform the hashing process 2¹⁰ = 1024 times.
This is why our password is always different. How does our compare function tell whether the hash is correct or not? Let’s understand that now.
How does Compare Function verify the password?
Given the bcrypt hash:
$2b$10$<22-character salt><hashed password>
Extract the Salt and Salt Rounds: The compare function first extracts the salt rounds (e.g.,
10
) and the salt (the 22-character string).Hash the Provided Password: The function then hashes the provided password using the extracted salt and salt rounds. It performs the same number of iterations as defined in the salt rounds.
Compare Hashes: Finally, the newly generated hash is compared with the stored hash. If they match, the password is correct. If not, the password is incorrect.
Conclusion
Since bcrypt hashes the password with the same salt, the comparison works because the generated hashes will be identical if the password is correct.