Secure Password Hashes

Created: 01.10.2016

In this article, I will show you step by step how to setup a JSF 2.3 project in IntelliJ and run it on a local Payara application server.

Password hashing is a common technique to store passwords in a database. If a third party gets access to the database, it cannot directly use the hashes to authenticate as the corresponding user. Since hash functions are one way functions, an attacker cannot simply compute the password given the hash. Instead, they usually use a list of common passwords, compute their hashes and see if one or more of them match with the leaked hashes.
To avoid computing such a list over and over, an attacker can just pre-compute it. Such rainbow tables can be really big as drive space is cheap. A hash can be broken with such tables in a little amount of time. That’s why applications use a salted hashing technique to protect user passwords.

A salt is a random number or string, which will be concatenated with the password before the password is hashed. So the password that will be stored in the database looks like this:

String hashedPassword = hashPasswordAndSalt(password, salt);

It does not matter if the salt is appended or prepended as long as it is consistent. A salt should have the following properties:

  • It is random (no statistical patterns).
  • The length is sufficient.
  • It is unique for each user.

The salt will also be stored in the database. It needs no protection at all, so it can be stored in a clear form. A record in the database could look like this:

user(userId, name, hashedPassword, salt)

The salt should be generated by a Cryptographic Pseudo Random Number Generator. There is one in the package. An implementation could look like this:

public static String createSalt(){  		
	SecureRandom random = new SecureRandom();          
	byte[] salt = new byte[SALT_BYTE_SIZE];          

Hex.encodeHexString() is part of the apache codec library which comes in pretty handy. The length of the salt depends on the computational power of the attacker. I use a length of 24 Byte in my examples, which should be sufficient for the number of users and to prevent building rainbow tables in a reasonable amount of time. Of course, this might change with technological improvements.

Finally, you need to select an appropriate hashing function. The list of appropriate functions changes over time, as of today SHA256, SHA512, SHA3, WHIRLPOOL, … are considered secure. To use these functions in java you can access the MessageDigest class:

public static String hashPasswordAndSalt(String password, String salt){      
	MessageDigest md;      
	try {          
		md = MessageDigest.getInstance("SHA-256");                    
		byte[] result = md.digest( (password+salt).getBytes());                    
		return(Hex.encodeHexString( result ));      
	} catch (NoSuchAlgorithmException e) {          
	return null;