Keywords: bcrypt | password security | salt mechanism | rainbow table attack | password hashing
Abstract: This article provides an in-depth exploration of the built-in salt mechanism in the bcrypt password hashing algorithm. By analyzing the generation, storage, and verification processes of salts, it explains how bcrypt effectively resists rainbow table attacks through random salts and cost factors. The article details the structural composition of bcrypt hash strings, including version identifiers, cost factors, salt values, and ciphertext encoding methods, and illustrates the complete password verification workflow through code examples. It also clarifies common developer misconceptions about salt storage, highlighting the design advantages of bcrypt's integrated storage of salts and hash values.
Fundamental Principles of bcrypt's Built-in Salt Mechanism
bcrypt, as a hashing algorithm specifically designed for password storage, innovates by integrating salt values directly into the hash output. This design addresses the complexity of separately storing salt values in traditional password hashing schemes.
Salt Generation and Function
In bcrypt's workflow, a 128-bit random salt is first generated. As demonstrated in the OpenBSD implementation, the salt is generated using an arcfour keystream, seeded with random data collected by the kernel from device timings. The primary role of the salt is to ensure that even if two users use the same password, their generated hash values will be completely different, thereby effectively preventing rainbow table attacks.
Structural Analysis of bcrypt Hash Strings
A typical bcrypt hash string example is: $2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
This string uses "$" as a delimiter and contains three key components:
2a: Identifies the bcrypt algorithm version used10: Cost factor, indicating the number of iterations of the key derivation function (210 times)vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa: Salt value and ciphertext concatenated and encoded in modified Base64
Detailed Password Verification Process
When a user attempts to log in, the system extracts the cost factor and salt value from the stored hash string. It then uses the input password, extracted salt, and cost factor to re-derive the encryption key, and encrypts the same known string with this key. If the generated ciphertext matches the stored ciphertext, the password verification is successful.
Code Implementation Example
The following example demonstrates the complete usage workflow of bcrypt:
// Password hashing process
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(plainTextPassword, salt);
// Password verification process
const isValid = await bcrypt.compare(loginPassword, storedHash);
It is important to note that during the verification process, developers do not need to manually provide the salt value, as it is already built into the stored hash string. The bcrypt library automatically parses the hash string and extracts the salt value for password verification.
Comparison with Traditional Schemes
Unlike traditional password hashing schemes such as PBKDF2, bcrypt uses the derived key to encrypt known plaintext instead of directly storing the derived key. This design allows bcrypt to maintain the same level of security while simplifying the management and storage of salt values.
Security Recommendations
Although the example uses a cost factor of 10, in practical applications, it is recommended to use a higher cost factor (such as 12 or higher) to account for the continuous growth in computational power. A higher cost factor increases the difficulty of brute-force attacks, thereby providing better security protection.