The Structure of a Salted Hash in bcrypt
The Structure of a Salted Hash in bcrypt
When you hash a password using bcrypt, the resulting hash has a very specific structure. This structure contains several important components, including:
- The algorithm identifier (which denotes the hashing algorithm and its parameters).
- The cost factor (defining the “work factor” for hashing).
- The salt (a random string ensuring uniqueness).
- The hashed password (the result of the hashing algorithm applied to the password and the salt).
Let’s break down the structure of a typical bcrypt hash and explain how it secures passwords.
bcrypt Hash Format
A bcrypt hash looks like this:
$2b$10$TKh2dD0.vLXu1mN1sojJ.eZTe5EowYsohMjIjP2lrd0LrkMC5cW2K
Breaking Down the Components
$2b$
— The Algorithm Identifier:
- This prefix indicates the version of the bcrypt algorithm used.
- The “2” signifies bcrypt, and “b” specifies the specific variant. Earlier versions may use
$2a$
, while newer implementations use$2b$
for improved compatibility and performance.
2. 10$
— The Cost Factor:
- The cost factor (also called the “work factor”) determines the number of iterations bcrypt uses to hash the password.
- A value of
10
means bcrypt hashes the password 1,024 times (2^10 iterations). Each increment doubles the time required to compute the hash. - This feature ensures that hashing remains computationally expensive, deterring brute-force attacks. Today, a cost factor of 12 is widely recommended, as it balances security and performance for modern systems.
3. TKh2dD0.vLXu1mN1sojJ
— The Salt:
- This random string ensures that even if two users have the same password, their hashes will differ.
- bcrypt automatically generates a unique salt for each password and appends it to the hash. This prevents the use of precomputed tables (like rainbow tables) for reversing hashes.
4. eZTe5EowYsohMjIjP2lrd0LrkMC5cW2K
— The Hashed Password:
- This is the final result of bcrypt’s algorithm after combining the salt with the password and performing the specified number of iterations.
- The hash is what’s stored in the database and compared during authentication.
Full Breakdown Example
Let’s analyze the following bcrypt hash:
$2b$10$TKh2dD0.vLXu1mN1sojJ.eZTe5EowYsohMjIjP2lrd0LrkMC5cW2K
- Algorithm identifier:
$2b$
- Indicates bcrypt version 2b.
2. Cost factor: 10$
- Uses 1,024 iterations for hashing.
3. Salt: TKh2dD0.vLXu1mN1sojJ
- A unique string generated to ensure hash uniqueness.
4. Hashed password: eZTe5EowYsohMjIjP2lrd0LrkMC5cW2K
- The final result of the bcrypt hashing process.
How bcrypt Uses This Structure for Authentication
When a user logs in and submits their password, bcrypt validates the input as follows:
- Extract the salt and cost factor:
- These are embedded within the stored hash. For example,
TKh2dD0.vLXu1mN1sojJ
is the extracted salt.
2. Rehash the entered password:
- bcrypt hashes the entered password using the extracted salt and cost factor.
3. Compare the hashes:
- If the newly generated hash matches the stored hash, the password is correct. Otherwise, authentication fails.
Why Is This Structure Important?
- Salt as a Key Security Feature:
- Salts ensure that every hash is unique, even for identical passwords. Without a salt, attackers could easily identify passwords using precomputed hash tables.
2. Cost Factor for Increased Security:
- A higher cost factor makes brute-force attacks computationally expensive. For example:
- Cost factor
10
: ~1,024 iterations. - Cost factor
12
: ~4,096 iterations. - Doubling the cost factor doubles the hashing time, significantly increasing the difficulty of brute-forcing passwords.
3. Irreversibility:
- bcrypt hashes cannot be reversed to obtain the original password. Instead, password verification relies on hashing the input password and comparing it to the stored hash.
Example Code for Registration and Login
Here’s how bcrypt handles password hashing during registration and login.
Registration (Hashing the Password)
When a user signs up:
- A unique salt is generated.
- The password and salt are combined and hashed.
Code Example:
const bcrypt = require('bcryptjs');
const password = 'userPassword123';
const saltRounds = 10;
bcrypt.hash(password, saltRounds, (err, hashedPassword) => {
if (err) throw err;
// Store hashedPassword in database
console.log('Stored Hash:', hashedPassword);
})
Login (Validating the Password)
During login:
- Retrieve the stored hash from the database.
- Compare the entered password with the stored hash.
Code Example:
const enteredPassword = 'userPassword123';
const storedHash = '$2b$10$TKh2dD0.vLXu1mN1sojJ.eZTe5EowYsohMjIjP2lrd0LrkMC5cW2K';
bcrypt.compare(enteredPassword, storedHash, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
console.log('Password is correct!');
} else {
console.log('Invalid password.');
}
});
Conclusion: Why Understanding bcrypt’s Salted Hash is Essential
bcrypt’s salted hash structure ensures that passwords are stored securely by:
- Combining a unique salt with each password to prevent precomputed attacks.
- Using a configurable cost factor to make brute-forcing impractical.
- Embedding the salt and cost factor within the hash for easy verification without additional data storage.
This self-contained and robust design makes bcrypt one of the most reliable tools for securing user credentials in modern applications. By leveraging its features effectively, developers can confidently protect their users’ data from potential attacks.