Yoav Ravid

Almost Everything is Knowable; Nothing is Absolutely Certain

Better Password Peppering

Epistemic status: fairly confident. I'm not a cryptographer, but no one raised strong objections and I thought about it a bunch since first thinking about it.

Everyone talking about password peppering is missing a better method to implement it1

Whether you think peppers are good or bad, knowing this is valuable. If you think they're good, this is a better method to use them. If you think they're bad, this is a stronger version to argue against. The main point of this post isn't to endorse peppers (though I do think they're good), but to compare the common methods to an alternative one.

Terms and background, in short

Skip if you're familiar 

Hash: Secure password storage doesn't store passwords, so if the database leaks, the passwords aren't revealed. Instead you use a hashing function, which takes any password, and turns it into a seemingly random (very large) number, this is your hash, and this is what you store instead of the password. Hashes are hard to reverse, and unlike encryption, hashes don't have keys to decrypt them. When the user logs in, the password is hashed again and compared to the stored hash.

Salt: A random string that is added to the password before it's hashed, and is usually stored in plain text near the now salted hash (so each salt is connected to a user). When the user logs in the salt is again hashed with their password and compared to the stored hash. Salts prevent rainbow table attacks, and make the hashes of passwords shared by multiple users unique so each password has to be cracked individually. However, if the database is leaked and an attacker targets a specific user and is willing to bruteforce their password, a salt will do nothing to stop them, and the user will have to rely on the strength of their own password.

Pepper: A pepper is a secret salt that is stored without connection to a user (e.g. in a separate table in the database2, or not stored at all). Peppering is optional - it's not required for a secure system. If you choose to use them it should always be in addition to salts since peppering doesn't provide enough security on its own. The benefit of peppering passwords is that it makes it harder to crack individual salted-hashed passwords even in the case of a leak.

Common Approaches

There's two main approaches to peppering, both should be in addition to salting.

  1. You generate and store one really long number (128+ bits), and keep it secret. Then whenever you need to hash a user's password you add it to the password before hashing.
    • Pros: if attackers don't know the pepper it's impossible to crack any of the passwords.
    • Cons: If the attackers find the pepper it becomes useless, and if they know the salt and plain text password of some user (could even be themselves), and which hashing algorithm was used, they can potentially use that to brute force the pepper. Secrecy is a very bad security assumption.
  2. You generate a random string for each password and use it as the pepper, but don't store it at all, so every time the user logs in you basically have to brute force all the peppers until you find the right one. For it to not take ages, you use a small string, say 1-2 characters.
    • Pros: It makes the attackers X times slower for password they try to crack, because they have to try every possible pepper on every possible password to reject that password. On the other hand, when authenticating you only have to check, on average, 50% of the peppers to verify the password.  
    • Cons: the attackers will likely know which peppers are possible, since it's likely 1-2 characters out of the allowed character set, and because that specification will be somewhere in your codebase, which makes the secret vulnerable. Most likely, you'll use a ready-made protocol supplied by whichever framework you're using (this is, indeed, what you should do, instead of writing your own security system which will probably have exploitable bugs or oversights).

I think method #1 is better than method #2, but my method is better than both:

My method is a combination of the two:

Do note that I'm not saying no one has come up with this before, just that I didn't see it.

Generate and store some (say, ~100) really long numbers. When a user registers, you pick one of them at random and append it to their password (in addition to a salt) before hashing. Whenever they login you try each of the stored peppers until one works. 

If these are your users and their passwords:

Users: Password
User1 password
User2 qwerty

Then this how your database will look like:

Peppers (Hexadecimal):
d0f008977df53df5
61e71e00c6ca3e49
513c98b24377f966
7a0d272ec2b0c83a
...
Users: Salt Password3
User1 406d1d689f3b6026 274e6e7e99740e80dc0b8eb5e10252d02fe1a2e1afdddd6ccc4eac9d
User2 c009b7d01c61bd19 68f2508b725b6350b4a7b4ac96569c3c96f8228d0398ce42a4af70c9

For user1, pepper 3 was selected, so we hash and stored "406d1d689f3b6026password513c98b24377f966" (salt+password+pepper)4

For user2 pepper 1 was picked, so we hash and store "c009b7d01c61bd19qwertyd0f008977df53df5".

Notice that nowhere in the database do we store which peppers are used for which users.

When user1 tries to log in, we receive the password they give and append it to their salt. We go through our peppers, and each time append them to the salted password, hash the whole thing, and compare it against the stored hash. If we find a matching hash we let the user through, if we iterated through all the peppers and didn't find a matching hash we don't let the user through.

Pros over method #1: 

  • Your peppers aren't easy to crack anymore, even if one pepper is brute forced, there's still all the others that remain unknown.
  • If the peppers leak, then the attackers still don't know which pepper is used for which user, and so are still slowed down by the amount of peppers you chose to generate (reminder, attackers have to try all the peppers as they mainly need to reject passwords, you have to check 50% of peppers as you mostly need to verify passwords).

Pros over method #2: 

  • The peppers are practically impossible to guess, while still giving the benefit of having a lot of different ones.
  • This makes cracking even a weak password like '123' impossible without already knowing the pepper used or which peppers to check.
  • Authentication isn't slower since appending is quick and you choose the amount of peppers you use.
  • You don't lose much security from stored peppers since the possible peppers were already quite predictable with the common method.
  • You have better control over the amount of possible peppers, and it's easy to gradually add more peppers with time.

This is more secure than both methods, with little downside, and barely any increased complexity - Yet I wasn't able to find any source that describes something similar.


  1. I looked for anyone mentioning a method like it and couldn't find anything. 

  2. Many sources talk of storing the pepper "outside the database", and a previous version of this article used this phrasing as well (though did mention it's not strictly necessary). The reason that, as the rest of the article explains, conventional implementations require a secrecy assumption. Though storing it "outside the database" does make it less likely the pepper would leak if the database leaks, assuming that you can keep the pepper secret if you can't keep the passwords secret is just a bad and insecure assumption. The method I suggest still benefits from secrecy (so storing "outside the database" won't hurt), but doesn't require it. 

  3. I used SHA224 for the hash, just as an example. It's not a good hashing algorithm for passwords. 

  4. This likely isn't exactly the right way to hash the three values together, but that doesn't change the core of the method. 

How to solve the argument about what the algorithm should do Building Blocks of Politics - An Overview of Selectorate Theory