Using “pepper” to increase password storing security
Tags: java, security, password, database
Published: 2021-04-15 07:04:56

*Article originally posted o my personal website under [How to securely store the password using a salt and pepper](https://petrepopescu.tech/2021/02/using-pepper-to-increase-password-storing-security/)*

In a previous article I wrote [how to securely store a password in the database](https://petrepopescu.tech/2021/01/how-to-properly-store-a-password-in-the-database/). The article got the attention of many fellow developers and so I decided to improve it even more by writing this article. You see, even though it is very secure to store the password as a salted hash, there is an additional layer of security that can be added in order to make things even harder to crack: pepper.

[![Play Framework Java Course](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kp4dvf528qhlo0egwx4t.png)](https://courses.petrepopescu.tech/)

The “pepper” part is not meant to replace the salted hash, but to enhance the algorithm further in order to have the data stored in a more secure way and make it virtually impossible to use any leaked data.

### How to add pepper to your salted hash

The “pepper” is actually an encryption layer on top of the obtained hash. The algorithm is as follow: you hash the password, just as before. The resulting hash is then encrypted using a symmetric-key encryption algorithm. The resulted encripted data is the one that is actually stored in the database.

When you want to verify the user-submitted password, you redo the algorithm and compare the result with the stored encrypted-hash. If they match, the password entered is the correct one. The advantage is that not even the hash is in clear and you don’t have to decrypt it when validating the submitted password since the same values will be returned for the same inputs.

One thing to keep in mind though is that the password used for encrypting should NOT be stored in the database. This is critical since any DB dump or exposure will also leak the password and it will be easy to just decrypt all the hashes. It will still be only one layer defeated, but with a “pepper” we want to avoid even that.

### Implementing a “pepper” for your password hash

First, you will need to define the pepper. Again, do not store it in the same database. You can use configuration files, an external but secure system (like Hashicorp Vault or an HSM). One thing to keep in mind that the pepper should be rotated, so always assign a version to it.

In the table where you store the hashed password and the salt, also store the pepper version. This is so that you know what secret to use when re-crypting the user-submitted password and so that you can invalidate a password IF the pepper gets compromised. The column can be a simple INT() one.

Now, the java part.

```java
char[] pepper = readPepper();
String salt = CryptoUtils.generateSalt();
String passwordHash = CryptoUtils.generateHashForPassword(newUserDTO.getPassword(), salt, pepper));
```

The important stuff happens inside the generateHashForPassword() method. A simplified version ca be read below. It is a modified version of the one in the original article, but AES was used to encrypt the originally generated hash.

```java
public static String generateHashForPassword(String password, String salt, String pepper) throws NoSuchAlgorithmException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException {
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
    byte[] hash = secretKeyFactory.generateSecret(spec).getEncoded();

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKey key = new SecretKeySpec(pepper.getBytes(), "AES");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] cipherText = cipher.doFinal(hash);
    return Base64.getEncoder()
            .encodeToString(cipherText);
}
```

To validate that the password the user submitted during login is the same as the one provided during registration, you redo the entire algorithm. If the stored Base64 string is the same as the one calculated, the passwords are the same. No need to decrypt the stored data at all. The only thing to keep in mind is that the same pepper is used, something that can be done by reading the stored pepper version.

### Conclusions

Further increasing the security of the stored passwords is not that complicated. Indeed, it adds more processing time, but not by much. It is small trade-off if you think of the added benefits. Just keep the pepper safe and if it get’s exposed, rotate it and re-encrypt everything.

*Article originally posted o my personal website under [How to securely store the password using a salt and pepper](https://petrepopescu.tech/2021/02/using-pepper-to-increase-password-storing-security/)*