What is a hash?
To store a password securely you need to encrypt it in some way so nobody, but the user will know their password. To do this encryption a cryptographic hash function is needed. A hash function maps an arbitrarily long input to a fixed-length output. A cryptographic hash function has a special attribute, that it’s a one-way function, so it cannot be inverted. In other words, the original value cannot be calculated from the hashed value.
One character difference between two strings will make the hashed strings
completely different, e.g:
password1 is hashed to 3ca4197139361dfa9200066fc86ad494 and
password2 is hashed to 767a9682d5a6faf085a93b700d847350
So the password checking will look like this:
- When the user creates a new account, their password is hashed and the hash is stored, not the password itself
- When the user logs in, their password is hashed, and the newly hashed password gets compared with the stored hash
There are several hash functions, but in this case do not use fast cryptographic hash functions, like SHA1, SHA256, SHA512, MD5, as they are suspect to brute-force attacks. The slower the algorithm, the longer it takes for an attacker to simply try and match all possible values. Use PBKDF2, bcrypt, scrypt or Argon2. In this tutorial you will write a hash function that
uses PBKDF2.
If you are a java developer, PBKDF2 (Password-Based Key Derivation Function 2) is an excellent algorithm to use. In PBKDF2 we can force the algorithm to behave slowly by increasing its iteration count.
This article teaches you how to hash passwords using the Java implementation of the PBKDF2 algorithm.
In simple words, PBKDF2 is a variant of the key stretching algorithm which uses a pseudorandom function to increase the computation power of the hashing for password storage.
Storing user passwords securely can be a challenging task. It is well known that as much as an attacker wants to gain access to a user’s password, the user wants to protect their password from being stolen. Password management tools such as one time password tokens and hardware tokens do exist but they are often expensive and are generally not convenient for everyday use.
Passwords can be the most valuable data to an attacker because stolen passwords can provide attackers the ability to bypass most of the security parameters that exist in the system.
The PBKDF2 algorithm includes a salt and iteration count. The iteration count determines the hashing time, which is deliberately made slow to prevent brute-force attacks. The salt is an extra input to the algorithm that makes each password unique by adding a small piece of random information that doesn’t affect security but requires additional computation.
Password hashing is a key component in web application security. A good hashing scheme will allow us to quickly authenticate a password while making it very hard (practically impossible) for a hacker to brute force the hashed value of a password. Hashing passwords is not enough though. We need to store our hashed passwords securely so that even if there is a breach attackers will only have access to useless data.
In this tutorial, you’ll learn how to properly store your passwords using the PBKDF2 algorithm.
Passwords are the most valuable data to an attacker. When stolen, passwords can provide attackers the ability to bypass most of the security perimeters that exist in the system.
By definition, a password is a secret word or phrase. It must be hidden from view and used by the user to protect his or her account. There are two important aspects to consider when generating and storing passwords:
The process of storing passwords securely is known as password hashing and the tool which we use for this purpose is called a Hashing Algorithm. The PBKDF2 algorithm is one such hashing algorithm that can be used to hash passwords in a highly secure manner
This tutorial will teach you how to use the PBKDF2 algorithm to hash passwords in a simple manner.
Unlike all other hashing algorithms, in PBKDF2 the length of the hash is not fixed. The length of the hash can be any number between the minimum and maximum seed count specified. Increasing this number decreases the rate of successful brute force attempts by increasing the number of iterations required to create a password hash.
By default, java security.MessageDigest provides a single-iteration PBKDF2 (PKCS5). One can increase this iteration count for improved security.
In the modern era of computing, passwords are important. When it comes to security, passwords are the most critical element of any system. If an attacker steals your password, they can bypass most security parameters and gain access to your data.
In this article, I will explain how to securely store passwords in a database by using an example.
Demonstration challenge
Your hash function has 4 arguments: password, salt, iteration, key length.
- password: it is the user’s password that will be hashed
- salt: a random string that mixes up a password’s hash, so if two users have the same password the two hashes won’t be the same
- iteration: the number of iterations, it determinates how slow the hash function will be, but be careful if the number of iterations is too high, it will use too many resources on the server. It should be around 10000 – 100000
- key length: required output length of the hash function. 256 or 512 key length is safe
Step 0:
You need to check whether the password argument is empty:
public static String hash(String password, byte[] salt, int iteration, int keylength) throws Exception{
if (password == null || password.length() == 0)
throw new IllegalArgumentException(“Empty password”);
}
Step 1:
Instantiate a SecretKeyFactory object that converts the secret keys of the specified algorithm, in our tutorial it is PBKDF2WithHmacSHA256
public static String hash(String password, byte[] salt, int iteration, int keylength) throws Exception{
if (password == null || password.length() == 0)
throw new IllegalArgumentException(“Empty password”);
SecretKeyFactory f = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);
}
Step 2:
Generate a SecretKey object from the provided key specification
public static String hash(String password, byte[] salt, int iteration, int keylength) throws Exception{
if (password == null || password.length() == 0)
throw new IllegalArgumentException(“Empty password”);
SecretKeyFactory f = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);
SecretKey key = f.generateSecret(new PBEKeySpec(password.toCharArray(), salt.getBytes(), iteration, keylength));
}
Step 3:
Return with the generated hash. It is a byte[], so you need to convert it to String type as the following code shows:
public static String hash(String password, String salt, int iteration, int keylength) throws Exception{
if (password == null || password.length() == 0)
throw new IllegalArgumentException(“Empty password”);
SecretKeyFactory f = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);
SecretKey key = f.generateSecret(new PBEKeySpec(password.toCharArray(), salt.getBytes(), iteration, keylength));
return Base64.getEncoder().encodeToString(key.getEncoded());
}
package hashingfunction;import java.security.SecureRandom;import java.util.Base64;import java.util.Scanner;import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory;import javax.crypto.spec.PBEKeySpec;/*** Cryptogenic Hashing function:** In this class we will use PBKDF2,* to encrypt users password** This function will be intentionally made slow, to make it withstand brute* force attacks.** @author Jake Adebayo*/public class HashingFunction {/*** @param password: it is the user’s password that will be hashed* @param salt: a random string that mixes up a password’s hash,* so if two users has the same password the two hashes won’t be the same* @param iteration: the number of iterations, it determinates how slow the hash function will be,* but be careful if the number of iterations is too high,* it will use too much resources on the server. It should be around 10000 – 100000* @param keylength: required output length of the hash function. 256 or 512 keyLength is safe** @return key* @throws Exception*/publicstaticStringhash(Stringpassword, byte[] salt, intiteration, intkeylength) throwsException {StringhashedPassword = “”;if (password == null || password.length() == 0)thrownewIllegalArgumentException(“Empty password”);if (iteration > 100000 || iteration < 10000)thrownewIllegalArgumentException(“Iteration should be in range (10000-100000)”);if (keylength != 256 && keylength != 512)thrownewIllegalArgumentException(“Keylength is not safe”);SecretKeyFactoryf = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);SecretKeykey = f.generateSecret(newPBEKeySpec(password.toCharArray(), salt, iteration, keylength));returnBase64.getEncoder().encodeToString(key.getEncoded());}/*** Creating random salt to prevent attacks,* from rainbow table* @return salt*/publicstaticbyte[] randomSalt() {byte[] salt = newbyte[16];SecureRandomsecure_random = newSecureRandom();secure_random.nextBytes(salt);return salt;}/*** Use this method if you don’t want to use* randomSalt()** @param salt* @return*/publicstaticbyte[] getSalt(Stringsalt) {returnsalt.getBytes();}// checks if entered password matches with hashed passwordpublicstaticvoidcheckPassword(Stringpassword, StringhashedPassword, byte[] salt, intiteration, intkeylength) throwsException {if (hashedPassword.equals(hash(password, salt, iteration, keylength)))System.out.println(“Password Matched!”);elseSystem.out.println(“Password Didn’t Match!”);}/*** @param args the command line arguments* @throws java.lang.Exception*/publicstaticvoidmain(String[] args) throwsException {finalintITERATION = 15000;finalintKEY_LENGTH = 256;Stringpassword = “jakespassword1234”;byte[] randSalt = randomSalt();StringhashedKey = hash(password, randSalt, ITERATION, KEY_LENGTH);System.out.println(“Your password is hashed to : ” + hashedKey);Scannerscanner = newScanner(System.in);System.out.println(“Enter your password : “);StringenterPassword = scanner.next();checkPassword(enterPassword, hashedKey, randSalt, ITERATION, KEY_LENGTH);}}