Because the access to special areas of Alumni (an application described in my book “Web Development with Java and JSF”) shall be restricted to members only, we need to restrict the access to authorized persons only. During the registration process, we ask the user to enter a password. This part is yet missing in the draft version of the registration form. Adding an input element is really easy. We’ll use an inputSecret in place of an inputText element.

But, since Alumni is exposed to the web, there is a potential risk, that somebody tampers the system. I guess everybody agrees that passwords need a special protection. They never should be stored in clear text format.

Although there is no 100% protection against crackers, is it possible to store passwords in a save way. We need to

1. strongly encrypt passwords
2. grant no access to any decryption
3. use an algorithm which takes some time to calculate
4. calculate different hashes although two users may have chosen the same password
5. use a algorithm to verify the password which takes almost the same time regardless of the password length

Encryption without any possible decryption, these goals could be achieved by a hash function. A purist may state, a hash is something other than an encryption. But it still calculates an “encrypted” value. Choosing the right algorithm we can reduce the risk of retrieving the same hash for two different passwords. For example, using SHA512 the risk for such a collision tends to zero.
Implementing such a hash function is quite easy:

public static byte[] getSHAHash(String secret) {
  try {
    MessageDigest md = MessageDigest.getInstance("SHA");
    byte[] digest = md.digest(secret.getBytes("utf-8"));
    return digest;
  } catch (UnsupportedEncodingException | NoSuchAlgorithmException ex) {
    Logger.getLogger("HashUtils").log(Level.SEVERE, null, ex);
    throw new RuntimeException(ex);
  }
}

The strategy would be to store a hash into the database. If a non-authorized person gets access to the database, he can not read the passwords, only the hashes. Using a simple algorithm as shown above is not advisable. There are some drawbacks we have to consider.

A cracker might try to start a brute force attack by sending a massive amount of different password combinations until he hits the right one. The simple hash is calculated very fast and the attacker might try many passwords in a short period of time. Thus, we have to slow down the process of user authentication and authorization (authentication: is this the right user?, authorization: which rights does this user have?). If the whole turn-around takes apx. 0.5 to 1 second it would not hinder the user. But is dramatically slows down the attacker.

Or a cracker might has stolen the hashes. Supposed he knows which algorithm is used to calculate the hashes, he now can use a brute force attack against the hashes. Again, we need to slow down this process to prevent the cracker from finding valid passwords. Whilst we could have delayed the user authentication at any place, now the only chance is to use a hashing algorithm which takes a long time. Pure SHA is much to fast to reach this goal.

If the cracker finds a valid password and this hash is used by more than one user, the cracker gains access to multiple accounts. To prevent this, we need to generate a different hash for different users although they may have chosen the same password. This goal can be achieved by “salting” the password. Suppose you have a string *salt* with a random value. You may calculate the hash by adding that salt to the password, e.g.

byte[] hash = getSHAHash(salt + secret)

Since we need the salt to calculate the correct hash, we need to store the salt somewhere. This might be within the same table where we store the password hash.

For a given password, the hash function always calculates the same hash.
Thus, it wold be possible to store phrases and their hashes. Then, you may lookup the password by querying this database with a hash. Such tables are known as “rainbow tables” and are available online for download at several places. A short search for “rainbow tables download” will list a lot of URLs. A salted password offers a protection against such rainbow tables, too.

Putting this together, Alumni uses the PBKDF2 (Password-Based Key Derivation Function 2) algorithm.

public static byte[] hashPassword(String password, byte[] salt, 
                                  int iterations, int keyLength) {
  try {
    SecretKeyFactory skf = SecretKeyFactory.
        getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 
                                     iterations, keyLength);
    SecretKey key = skf.generateSecret(spec);
    return key.getEncoded();
  } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) {
    Logger.getLogger("HashUtils").log(Level.SEVERE, null, ex);
    throw new RuntimeException(ex);
  }
}

By setting the iterations to a high value, the calculation would be slowed by additional rounds of calculation. On my development computer, a value of apx. 100000 iterations will take 0.5 seconds. Using 100047 or a similar number of iterations wont affect the felt time but produces a different hash. I assume such numbers would be used more rare than smooth numbers and help to improve the security.

The delay depends on your machine. Thus, don’t copy this value.
You need to figure out the best value for your machine.

KeyLength determines the length of the output. Alumni uses 1024.

Although the sketched approach might not apply the high requirements of a banking application, it is fine for a social application like Alumni.

This text is taken from my book “Web Development with Java and JSF”.