Cannot let the new backend developer get access of everyone’s password
🔐 What is password hashing?
Hashing is a one-way cryptographic function that transforms a password into a fixed-size, irreversible value (the hash). The idea is:
- You never store the actual password.
- You hash the password on registration and store only the hash.
- On login, you hash the user input again and compare it to the stored hash.
graph TD A[Password Sent By User] --> B[SHA 256 Taken of the password] B --> C[Hash & salt is stored in the db ]
So let’s make a module
- Hashes Password
Code ins java
package in.abhi8290.helloworld.shared.util;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Objects;
public class hashUtil {
private static final int SALT_LENGTH = 16; // 128 bits
private static final int HASH_LENGTH = 256; // bits
private static final int ITERATIONS = 65536;
private static final String ALGORITHM = "PBKDF2WithHmacSHA256";
// Generate a random salt
public static byte[] generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
return salt;
}
// Hash the password with the given salt
public static String hashPassword(String password , byte[] salt) throws Exception {
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, HASH_LENGTH);
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
byte[] hash = factory.generateSecret(spec).getEncoded();
return Base64.getEncoder().encodeToString(hash);
}
public static String getHashedPasswordWithSaltAndAlgorithm(String password) throws Exception {
byte[] salt = generateSalt();
return ALGORITHM + "$" + ITERATIONS + "$" + encodeSalt(salt) + "$" + hashPassword(password, salt);
}
public static boolean verifyPassword(String password, String hash) throws Exception {
String[] splittedString = hash.split("\\$");
byte[] salt = Base64.getDecoder().decode(splittedString[2]);
String savedHash = splittedString[3];
return Objects.equals(hashPassword(password, salt), savedHash);
}
// Encode salt to store it with the hash
public static String encodeSalt(byte[] salt) {
return Base64.getEncoder().encodeToString(salt);
}
// Decode salt when verifying
public static byte[] decodeSalt(String encodedSalt) {
return Base64.getDecoder().decode(encodedSalt);
}
}Imports
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import java.util.Base64;These are required for:
- Cryptographic hashing (
SecretKeyFactory,PBEKeySpec) - Secure salt generation (
SecureRandom) - Encoding/decoding salt and hash to/from Base64
Class and Constants
public class hashUtil {
private static final int SALT_LENGTH = 16; // 128 bits
private static final int HASH_LENGTH = 256; // bits
private static final int ITERATIONS = 65536;
private static final String ALGORITHM = "PBKDF2WithHmacSHA256";SALT_LENGTH: Size of the random salt (16 bytes = 128 bits)HASH_LENGTH: Output hash size in bitsITERATIONS: Number of PBKDF2 iterations (makes hashing slower to resist brute force)ALGORITHM: Specifies the secure hash function
Method: generateSalt
public static byte[] generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
return salt;
}Generates a cryptographically secure random salt.
Method: hashPassword
public static String hashPassword(String password) throws Exception {
byte[] salt = generateSalt();
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, HASH_LENGTH);
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
byte[] hash = factory.generateSecret(spec).getEncoded();
return ALGORITHM + "$" + ITERATIONS + "$" + encodeSalt(salt) + "$" + Base64.getEncoder().encodeToString(hash);
}- Converts the password to a
char[](secure practice). - Uses the salt, iteration count, and desired hash length to configure
PBEKeySpec. - Generates the hash using
PBKDF2WithHmacSHA256. - Returns a single string:
algorithm$iterations$saltBase64$hashBase64
This encapsulates all data needed to later verify the password.
Method: encodeSalt
public static String encodeSalt(byte[] salt) {
return Base64.getEncoder().encodeToString(salt);
}Encodes the byte array salt to Base64 for easy storage.
Method: decodeSalt
public static byte[] decodeSalt(String encodedSalt) {
return Base64.getDecoder().decode(encodedSalt);
}Decodes a Base64-encoded salt string back to the original byte array (used during password verification).
🧂 What is a salt?
A salt is a random, unique value added to the password before hashing. It’s critical for two reasons:
-
Prevents rainbow table attacks: Attackers can’t use precomputed hash lists.
-
Ensures uniqueness: Even if two users have the same password, their hashes will be different because the salt is different.
In your code:
byte[] salt = generateSalt();Generates a 16-byte (128-bit) random salt per password.
🔁 What is PBKDF2?
PBKDF2 (Password-Based Key Derivation Function 2) is a standard for password hashing. It uses:
-
A base HMAC algorithm (like HmacSHA256),
-
A salt,
-
An iteration count (e.g. 65,536),
-
And a desired output length (e.g. 256 bits).
This makes brute-force attacks slower, because the hash takes more CPU time.
Your code:
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATIONS, HASH_LENGTH);
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
byte[] hash = factory.generateSecret(spec).getEncoded();This means:
-
Password + Salt are passed through PBKDF2 with 65,536 iterations
-
The output is a 256-bit hash
-
Result is base64-encoded and stored
🧱 How it all fits together
When a user registers:
-
Generate a random salt.
-
Hash their password using PBKDF2 with:
- Password
- Salt
- Iteration count
- SHA-256
-
Store the result:
PBKDF2WithHmacSHA256$65536$<salt>$<hash>
When a user logs in:
- Extract algorithm, iterations, and salt from stored hash string.
- Re-hash the input password using the same parameters.
- Compare the new hash to the stored hash (using constant-time comparison).
✅ Why this is secure
- Each password is uniquely hashed (thanks to the salt).
- Hashing is slow (iteration count), making brute-force infeasible.
- Algorithm (SHA-256) is cryptographically strong.
Let me know if you’d like a verifyPassword() implementation added to your class.
What are the ways people can get the password How to Name Things in Programming