How You Can Use Pepper to Further Secure Encrypted Passwords
Published: 2023-04-13 23:47:16

We already understand the importance of encrypting passwords before saving them in the database. It is the standard practice, and not doing so means putting the user's data at significant risk. Let's take America as an example, where 67% of internet users use the same password for all their online accounts. So if a hacker breaks into your system and gets access to the database, where the passwords are in plain text, they will have a 67% chance of using that password to log in to other popular online platforms. That's why it is necessary to hash the passwords before saving, so no one, including the people inside the organization, can view the passwords in plain text.

We usually encrypt passwords using hashing algorithms; MD5, SHA-1, and SHA-2 are some of the commonly used algorithms. Hashing a password makes it unrecognizable to the viewer, but does it guarantees the hashed password from being cracked? Let's understand how hashed passwords are still not 100% secure.

Recovering plain text from hashed text is impossible without infinite computational power. However, we can still reverse-engineer the process. There is something called Rainbow tables, a pre-computed table of commonly used passwords saved in a pair of plain text and hash. Let's look at an instance where you are the user on a system that just got hacked. The password you used on the system was a very commonly used password, "p@ssw0rD". The system hashed the passwords with MD5 before saving them in the database, so the password got saved as "54fd6fc0cfbb34bd6e5a6742d965b658".

After getting access to the hashed password, the hacker has no idea what it is in plain text, and here is where the rainbow table comes into use. Since you used a common password, there is a high chance it is already available in one of the many available rainbow tables. The hacker only needs to search for the hash (54fd6fc0cfbb34bd6e5a6742d965b658) in the rainbow tables. Matching the password hash in the table means getting the plain text. In simple words, your password got compromised. Now like 67% of American internet users, if you use the same password on other online accounts, you will be in deep trouble. We don't want this to happen to our users, so let's understand how to counter this problem.

![Working of a rainbow table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whllhhs9oe7to0k8ntks.png)

We have two answers to the problem; Salt and Pepper. Maybe you are already aware of Salt or have no clue. Either way, let's focus on Pepper.

I believe it is easier to understand a concept with a little snippet of code; the following is a bit of Javascript, it is super simple, and if you are familiar with basic programming, I am sure you will understand the concept.

We will be creating two functions, createHash, and verifyPassword.

Let's start with createHash. This function will convert the plain text to hashed text with a twist.

```
function createHash (plainText) {
  const character = selectRandomCharacter();
  const newPlainText = plainText+character;
  const hash = encrypt(newPlainText);
  return hash;
}
```

Assume that the selectRandomCharacter and encrypt functions already exist. The selectRandomCharacter function returns a character randomly selected between the range of a and z, and the encrypt function hashes the plain text using any algorithm.

As you can see, we get a randomly selected character, append it to the end of the plain text, and then hash the plain text. The extra character that we append is called the Pepper. It doesn't need to go at the end, it can also be prepended, or placed in between. It's your choice.

Let's look at the other function, the verifyPassword. It will check if the provided password in plain text matches the hashed password saved in the database. It's usually used during the login process.

```
function verifyPassword(plainText, savedHash) {
  const characterArray = getArrayOfCharacters(); // returns an array of characters between a and z
  for (let char in characterArray){
    const newPlainText = plainText+char;
    const hash = encrypt(newPlainText);
    if (hash == savedHash) return true;
  }  
  return false;
}
```

All we know is that a character, from between a to z, was appended, but we don't know which, so what the function does is that it loops over the range (a-z), append the character on each loop, and verifies if the hash of that new plain text matches the saved hash. When it finds a match, it will mean that the provided password in plain text is valid and returns true. If the loop ends without matching, it returns false.

I hope you got a clear idea of the concept. The good thing about Pepper is that no one, including the developers, knows which character got appended to the plain text before it was hashed and saved.

This small change makes a massive difference as the hashed passwords become many times more secure. The previously used common password "p@ssw0rD" may be hashed as "p@ssw0rDw", and instead of the hash being "54fd6fc0cfbb34bd6e5a6742d965b658", it will become "a3bf00d81e6c45200abee0f0738ff4e7". With Pepper, the hash of passwords will no longer be saved in their original form, so it is hard to imagine them being in the rainbow table.

![hashing process with and without pepper](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umjwez8dgwn6bjh3mnea.png)

With Pepper in place, you can rest easy because the passwords saved on your application have become multiple times difficult to compromise. Do understand that this is not a means to secure the system. Instead, it is a measure in case the system is hacked or compromised.

Until next time :)