跪拜 Guibai
← Back to the summary

BCrypt vs Argon2 in Spring Security: When Memory Hardness Matters

BCrypt or Argon2? In-Depth Analysis and Practical Comparison of Spring Security Password Encryption Schemes

Password storage is the first line of defense for application security. Choosing the wrong encryption scheme can turn user data into a "buffet" for attackers. This article provides an in-depth comparison of two mainstream password encryption algorithms to help you make the right choice.


1. Introduction: Why Is Password Encryption So Important?

In web application development, the way user passwords are stored directly relates to system security. If passwords are stored in plaintext or using simple hashing methods, attackers can easily obtain all user password credentials once the database is leaked.

Wrong practices:

Correct practices: Use computationally intensive (slow hashing) and adaptive password hashing algorithms, making each hash calculation consume significant resources, thereby greatly increasing the cost of brute-force attacks for attackers.

Spring Security provides us with several mature password encoders, among which the most notable are BCryptPasswordEncoder and Argon2PasswordEncoder. This article will conduct a comprehensive comparative analysis of both, from principles to practice.


2. In-Depth Analysis of BCryptPasswordEncoder

2.1 What Is BCrypt?

BCrypt is a password hashing function based on the Blowfish encryption algorithm, designed by Niels Provos and David Mazières in 1999. It is designed to be computationally intensive (slow hashing), specifically for password storage, to resist brute-force and rainbow table attacks. Spring Security recommends it as the preferred password encoder.

2.2 Core Principle: Deliberately "Slow"

The core idea of BCrypt is to be "deliberately slow" — making each hash calculation consume a certain amount of CPU time, thereby greatly increasing the cost of brute-force attacks for attackers.

1. Salt

2. Adaptive Hashing (Strength Factor / Rounds)

3. Output Format

The hash string output by BCrypt has the following format:

$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
|  |  |                             |
|  |  |                             └─ Hash value (31 bytes Base64 encoded)
|  |  └─ Salt (22 characters Base64 encoded, actual 16 bytes)
|  └─ Strength (10 = 2^10 rounds)
└─ Version ($2a$ = BCrypt)

2.3 Constructor Parameters

Parameter Type Default Value Description
strength int 10 2^strength rounds of iteration, controls computational intensity
secureRandom SecureRandom Random instance Random number generator used for generating salt, can be specified

Usage examples:

// Use default strength 10
new BCryptPasswordEncoder();

// Use strength 12 (more secure, but slower)
new BCryptPasswordEncoder(12);

// Specify strength and random number generator
new BCryptPasswordEncoder(12, new SecureRandom());

2.4 Notes and Best Practices

  1. Choose an appropriate strength: It is recommended to use 10 in the development environment and choose between 10~14 in the production environment based on server performance. Generally, it is advisable to keep a single verification under 1 second.
  2. Do not manually add salt: BCrypt handles salt automatically, no manual intervention by developers is needed.
  3. Password length limit: BCrypt supports a maximum input password of 72 bytes; anything beyond that will be truncated. It is recommended to validate at the application layer or hash long passwords first.
  4. Migration strategy: If an old system uses other encoding methods, you can use DelegatingPasswordEncoder to support multiple encoding formats and gradually migrate to BCrypt.
  5. Upgrading strength: When you need to increase strength, you can only re-encode the password the next time the user logs in. Existing hash values cannot be upgraded in place.

3. In-Depth Analysis of Argon2PasswordEncoder

3.1 What Is Argon2?

Argon2 is the winner of the Password Hashing Competition (PHC) in 2015, designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich. It offers three variants:

Spring Security uses Argon2id mode by default.

3.2 Core Advantage: Memory Hardness

Argon2's biggest breakthrough is explicitly controlling memory usage, which forces attackers to allocate a large amount of memory for each password guess, thereby completely blocking GPU parallel cracking. Although BCrypt is computationally slow, its memory usage is minimal, allowing GPUs to still perform batch parallel computations.

3.3 Constructor Parameters

Argon2 provides four independently adjustable parameters, much more flexible than BCrypt's single strength parameter:

Parameter Description Default Value
saltLength Salt length (bytes) 16
hashLength Hash length (bytes) 32
parallelism Degree of parallelism 1
memory Memory size (2^N KB), default 1<<12 = 4096 KB = 4 MB 1<<12
iterations Number of iterations 3

3.4 Output Format

The hash string output by Argon2 has the following format:

$argon2id$v=19$m=4096,t=3,p=3$c2FsdHNhbHRzYWx0$dGhlc2lzYWhhc2h2YWx1ZWZvcmFyZ29uMg
|         |      |               |               |
|         |      |               |               └─ Hash value (Base64 encoded)
|         |      |               └─ Salt (Base64 encoded)
|         |      └─ Parameters (m=memory(KB), t=iterations, p=parallelism)
|         └─ Version number (v=19)
└─ Algorithm ($argon2id$ = recommended mode)

Usage example:

// Parameter description:
// saltLength: Salt length (bytes), default 16
// hashLength: Hash length (bytes), default 32
// parallelism: Degree of parallelism, default 1
// memory: Memory size (2^N KB), default 1<<12 = 4096 KB = 4 MB
// iterations: Number of iterations, default 3
new Argon2PasswordEncoder(16, 32, 1, 1 << 12, 3);

Maven dependency:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>1.78.1</version>
</dependency>

4. Comprehensive Comparison: BCrypt vs Argon2

4.1 Comparison Overview

Dimension BCryptPasswordEncoder Argon2PasswordEncoder
Algorithm Basis Blowfish cipher algorithm Argon2id (PHC winner)
Year of Birth 1999 2015 (Password Hashing Competition winner)
Adaptive Parameters strength (log2 rounds) saltLength / hashLength / parallelism / memory / iterations
Memory Hardness ❌ Low (does not consume much memory) High (configurable memory consumption, strong resistance to GPU/ASIC)
CPU Hardness ✅ High (adjustable) ✅ High (adjustable)
Parallelism Control ❌ Not supported ✅ Supports parallelism parameter
GPU Attack Resistance Medium Strong (memory hardness requirement renders GPU parallelism ineffective)
ASIC Attack Resistance Medium Strong
Side-Channel Attack Resistance Weak Strong (Argon2 design considers timing attacks)
Spring Boot Version No extra dependency (bundled with spring-boot-starter-security) Requires spring-security-crypto 5.x+ (built-in since Spring Boot 2.7+)
Default Parameter Security strength=10 (average) saltLength=16, hashLength=32, parallelism=1, memory=1<<12, iterations=3 (relatively secure)
Output Length Fixed 60 characters Variable (depends on parameter configuration)
Community Maturity ⭐⭐⭐⭐⭐ Nearly 20 years of extensive validation ⭐⭐⭐⭐ Widely recommended, but relatively shorter practice time
Password Length Limit 72 bytes No limit

4.2 Why Is Argon2 Considered More Advanced?

  1. Memory Hardness: The core design of Argon2 is to explicitly control memory usage, which forces attackers to allocate a large amount of memory for each password guess, thereby completely blocking GPU parallel cracking. Although BCrypt is computationally slow, its memory usage is minimal, allowing GPUs to still perform batch parallel computations.

  2. Three Independently Adjustable Dimensions: Argon2 provides three independent parameters: time cost (iterations), memory cost (memory), and parallelism (parallelism), whereas BCrypt has only one strength parameter. This means you can more finely balance security and performance.

  3. Side-Channel Attack Resistance: Argon2's memory access pattern is data-dependent, making it difficult for attackers to infer password information through side-channel means like cache timing.

  4. No Password Length Limit: BCrypt truncates passwords over 72 bytes, while Argon2 has no such limit.

4.3 Why Is BCrypt Still Widely Used?

  1. Mature Ecosystem: BCrypt has mature implementations in almost all languages and frameworks, having undergone nearly 20 years of large-scale production validation.
  2. Sufficiently Secure: For the vast majority of application scenarios, BCrypt (strength ≥ 10) is already secure enough, with very few public cases of being cracked.
  3. Zero Configuration: In Spring Security, you can directly new BCryptPasswordEncoder() without needing to understand complex parameters.
  4. Predictable Performance: The output is a fixed 60 characters, the hash length is consistent, and database field design is simple.

5. Practical Selection Recommendations

5.1 Scenario Decision Table

Scenario Recommendation Reason
Rapid Prototyping / Small Projects BCrypt (strength=10) Simple, reliable, sufficient
Medium-Sized Enterprise Projects BCrypt (strength=12~14) Sufficient security, mature ecosystem
High-Security / Compliance Projects Argon2 Memory hardness, stronger GPU/ASIC resistance
Passphrase Scenarios Argon2 No 72-byte limit
Hybrid Transition Schemes DelegatingPasswordEncoder Supports coexistence of multiple formats, gradual migration

5.2 Complete Spring Security Configuration Examples

BCrypt Configuration:

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder bCryptPasswordEncoder() {
        // strength=12, recommended for production environment
        return new BCryptPasswordEncoder(12);
    }
}

Argon2 Configuration:

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        // saltLength=16, hashLength=32, parallelism=1, memory=1<<12=4MB, iterations=3
        return new Argon2PasswordEncoder(16, 32, 1, 1 << 12, 3);
    }
}

5.3 Comparison with Common PasswordEncoders

Encoder Algorithm Adaptive Memory Requirement Recommended Scenario
BCryptPasswordEncoder Blowfish + Salt ✅ Adjustable Low General password storage (preferred)
Pbkdf2PasswordEncoder PBKDF2 + Salt ✅ Adjustable Low Compatibility with legacy systems
SCryptPasswordEncoder SCrypt + Salt ✅ Adjustable High Stronger immunity to ASIC/GPU attacks
Argon2PasswordEncoder Argon2id ✅ Adjustable High Winner of the 2015 Password Hashing Competition, currently most recommended
DelegatingPasswordEncoder Multiple formats Depends on delegate Depends on delegate Password format migration (transition from old schemes)

6. Summary

Comparison Item BCrypt Argon2
✅ Advantages Mature ecosystem, zero configuration, predictable performance Memory hardness, flexible parameters, no password length limit
❌ Disadvantages Low memory hardness, 72-byte password limit Depends on Bouncy Castle, complex parameter configuration
🎯 Best Scenario Small to medium projects, rapid prototyping High-security requirements, new projects, passphrase scenarios

Final Recommendation: If your project already uses BCrypt and has not encountered security bottlenecks, there is no need to forcibly migrate to Argon2. If you are starting a new project from scratch and have high security requirements, prioritize Argon2PasswordEncoder. Spring Security provides native support for both, and the switching cost is very low.

Remember: There are no absolutely secure algorithms, only relatively secure configurations. Regardless of which scheme you choose, regularly evaluating and adjusting parameters is key to ensuring password security.