Hashing is a cryptographic function which converts any amount of data into a fixed length hash which cannot be reversed. Hashing enables us to validate if the input has changed even a little bit, if changed then the resulting hash will be different. In this article we will learn the technique of Salted Password Hashing.
Hashing is great for protecting the passwords but has a minor flaw due to its deterministic nature. Let’s say if John and Smith uses the same password ‘secret1234’ then the result hashing will be ‘390d4757bf1b75e305984c99cdedfb1e7c201a2d143a53cfbc35075fa5f9a56f390d
4757bf1b75e305984c99cdedfb1e7c201a2d143a53cfbc35075fa5f9a56f’.
If a hacker was able to break the hash using any one of the technique such as dictionary attack, brute-force attack, Lookup Tables, Reverse Lookup Tables or Rainbow Tables then he can access all the accounts that uses the same hash.
To mitigate the above issue we could Salt the password, a Salt is a fixed-length secure random string which is added to the password before hashing and hence the hash will be different for the same password.
John’s hash would be de0766b1d4eff33680b2a0d6f408ff6471d6898e83cf2a3f4e647fac5b269eed and
Smith’s has would be 0dfaede04a91ee60d9652be9525af86518cc695dd80c06d9066acca9e009c9fb
Despite using the same password the resulting hash differs. Lets understand how to add Salted Password Hashing.
Java Salted Password Hashing
package com.javainterviewpoint; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class HashExample { public static void main(String[] args) { String password = "secret1234"; MessageDigest md; try { // Select the message digest for the hash computation -> SHA-256 md = MessageDigest.getInstance("SHA-256"); // Generate the random salt SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); // Passing the salt to the digest for the computation md.update(salt); // Generate the salted hash byte[] hashedPassword = md.digest(password.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte b : hashedPassword) sb.append(String.format("%02x", b)); System.out.println(sb); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
- The MessageDigest class provides the functionality of a message digest algorithm, we will be getting the MessageDigest instance by passing the algorithm to the getInstance() method. The list of the algorithm which can be passed can be found in this link. In our case we are using SHA-256
MessageDigest md = MessageDigest.getInstance("SHA-256");
- As per OWASP, Salt should be generated using a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG), for Java the CSPRNG is java.security.SecureRandom. We will be creating a new instance for SecureRandom class and the nextByte() method generates the random salt.
SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt);
- We will be adding the salt to input using the update() method of MessageDigest
md.update(salt);
- Once we have added the salt we can generate the hashed password using the digest() method.
byte[] hashedPassword = md.digest(password.getBytes(StandardCharsets.UTF_8));
Output :
Run 1:
5f60d113a45fa44055ce2359c51bda57aaf4217281979db824bc2ecb771b736f
Run 2:
ca1cf58110e43860995df6df8e16c62f466f5967b520155e2c93b57f7ac72e8e
So each time we run the code the output will be different hashes.
Points to Remember
While Storing the password
- Generate a long random salt using SecureRandom
- Use the Hash function such as SHA256 to hash both Salt and Password together
- Save both the Salt and the Hash separately in the database.
While Validating the password
- Retrieve the Salt and Hash from the database
- Use the same Hash function (SHA256) which is used while generating the hash
- Generate a new Hash with new password provided and the Salt retrieved from the database.
- Now compare the new hash with the hash from the database. If they match, then password provided is correct. Otherwise, the password is incorrect.
MR-OBVIOUS says
So its basically useless if you want to store a password for later comparison or compare files hash because it will give you a different answer each time???
Chris says
For storing hashed with salt passwords in the DB, the salt would also have to be stored in the DB correct?
Or else when the user tries to log in after creating his account and password, how would the system know his login entered afterwards matches an existing entry if the salt is generated randomly using the code above?
javainterviewpoint says
Yes the salt also has to be stored separately. So that it can be used to validate the user.