Chapter 7.2☕ 14 min read

Password Encoding with BCrypt

If your database gets hacked, BCrypt ensures your users' passwords remain safe.

01The Concept: Hashing vs Encryption

The Hyderabadi Irani Chai Masala Analogy:

Imagine you have a secret recipe for Irani Chai masala.

  • Encryption is like locking the masala in a safe. If someone gets the key, they can unlock it and see the exact ingredients (reversible).
  • Hashing (BCrypt) is like cooking the masala into the chai. Once it's mixed and cooked, no one can ever separate the masala back out into its original powder (irreversible).

Spring Security uses BCrypt to mix the password into an unreadable string. Even if a hacker steals the database, they can't un-cook the chai to get the password back. When the user logs in, Spring cooks their input the exact same way and checks if the final chai tastes the same.

02Technical Explanation
  1. BCryptPasswordEncoder: The Spring class that hashes passwords.
  2. Salting: BCrypt automatically adds a random “salt” (random string) to the password before hashing. This means if two users have the password “password123”, their hashes in the database will look completely different. This stops Rainbow Table attacks.
  3. Matches: To verify a login, you don't decrypt the hash. You use encoder.matches(rawPassword, hashedPassword).
03Full Working Code: Hashing Passwords
package com.devinhyderabad;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Configuration
public class SecurityConfig {

// 1. Expose BCryptPasswordEncoder as a Spring Bean
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

// --- Usage Example in a Service ---
@Service
class UserService {

private final PasswordEncoder passwordEncoder;

// Spring injects the BCryptPasswordEncoder here
public UserService(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}

public void registerUser(String rawPassword) {
// 2. Hash the password before saving to DB
// e.g., "myPassword123" becomes "$2a$10$N9qo8uLOickgx2ZMRZoMye..."
String hashedPassword = passwordEncoder.encode(rawPassword);
System.out.println("Saving to DB: " + hashedPassword);
}

public boolean login(String rawPassword, String dbHashedPassword) {
// 3. Verify login without ever decrypting the DB password
return passwordEncoder.matches(rawPassword, dbHashedPassword);
}
}
04Code Walkthrough

The code above demonstrates:

  • PasswordEncoder Bean: BCryptPasswordEncoder is registered as a Spring bean. It automatically handles salt generation and hash computation.
  • Registration: passwordEncoder.encode() produces a hash like $2a$10$...”. The $2a$ identifies BCrypt, 10 is the work factor (higher = slower = more secure).
  • Login: matches() compares the raw password against the stored hash by re-hashing the input with the same salt embedded in the hash string.
05Why It Matters / Interview Note

Interview Question: “Why is BCrypt preferred over MD5 or SHA-256 for passwords?”

Answer: MD5 and SHA-256 are designed to be extremely fast. Hackers can guess millions of passwords per second against a stolen MD5 hash. BCrypt is intentionally designed to be slow (it has a “work factor” or strength parameter). It takes a fraction of a second to hash one password, making brute-force attacks computationally unfeasible. BCrypt also automatically handles salting.

Enterprise Note: If you migrate an old database with MD5 passwords, the standard enterprise practice is to use DelegatingPasswordEncoder. It allows the system to read old MD5 hashes, but when the user logs in, it silently upgrades their password to BCrypt in the background.

Key Takeaways

  • ✅ BCrypt is a one-way hash function (irreversible), unlike encryption
  • ✅ BCrypt automatically adds a random salt to prevent Rainbow Table attacks
  • ✅ BCrypt is intentionally slow to make brute-force attacks unfeasible
  • ✅ Use passwordEncoder.matches() for login verification, never decrypt
  • ✅ DelegatingPasswordEncoder handles migration from older hash algorithms