43

Update: There is a better way to add a server side key, than using it as a pepper. With a pepper an attacker must gain additional privileges on the server to get the key. The same advantage we get by calculating the hash first, and afterwards encrypting the hash with the server side key (two way encryption). This gives us the option to exchange the key whenever this is necessary.

For hashing passwords in a database, i would like to add a pepper to the hash function. Of course this pepper will be additionally to the unique salt.

The reason why i want to add a pepper is, that it prevents a dictionary attack, in case that the attacker has only access to the database, but not to the server (typical for Sql-Injection). In my opinion this is better than a hash without pepper, even if the pepper is only hardcoded (to avoid code complexity).

Now i wonder, how the pepper should be applied correctly, is it correct to just append the pepper to the password before hashing?

1. Concatenating password and pepper

$passwordHash = bcrypt($password . $pepper, $salt);

A reason against this could be, that passwords bigger than the bcrypt limit (55 characters) will not get the pepper, although passwords of this length are propably not in a dictionary anyway. Because of this limit, the pepper is added after the password and not before. Another reason could be, that if the attacker knows the pepper, he also knows the ending of all our peppered passwords.

2. Combine password and pepper with hash

$passwordHash = bcrypt(hash('sha256', $password . $pepper), $salt);

So we could use a hash function to combine password and pepper, before hashing. Is it appropriate to use sha256, or which hash function would be ideal, when we want to use bcrypt afterwards?

3. Combine password and pepper with hmac

$passwordHash = bcrypt(hash_hmac('sha256', $password, $pepper), $salt);

Often a hmac is the recommended solution, is there any advantage over using SHA256 directly? Since we only want to combine password and pepper, and the security comes later from the bcrypt, i cannot see any apparent advantage.

Any helpful hints are much appreciated.

martinstoeckli
  • 5,149
  • 2
  • 27
  • 32
  • Isn't `hash_hmac('sha256', $pepper, $password)` will be more correct (use $pepper as HMAC's key)? – Powerman Apr 24 '14 at 19:31
  • Is there any difference for security between `bcrypt(hmac($pepper, $password), $salt)` and `hmac($pepper, bcrypt($password, $salt))`? – Powerman Apr 24 '14 at 19:32
  • @Powerman - There is a better way to add a server side key to the hash, i updated my answer to point it out. Doing it this way you cannot decrease security, because in the worst case an attacker just gets the original hashes. I wrote a [tutorial](http://www.martinstoeckli.ch/hash/en/index.php) about safely storing passwords, where i tried to describe it more indepth. – martinstoeckli Apr 25 '14 at 06:28
  • Nice tutorial, but why do you think encrypt() is any way better than hmac()? At a glance it's much worse: 1) it's (needlessly, after bcrypt) slower; 2) when attacker know pepper he can just decrypt() to get bcrypt's result and then bruteforce using just bcrypt, while with HMAC he will need to do bruteforce using hmac+bcrypt which complicate things a little for him; 3) with wrong encryption algo or mode (CBC/EBC) it may be possible to analyse encrypted hashes from db to reveal encryption key (pepper). – Powerman Apr 25 '14 at 13:19
  • @Powerman - The purpose of the key is, that the attacker needs to gain additional privileges on the server (he needs the key, the database alone won't do), not to make the hash more safe (this is the job of BCrypt). Of course if the encryption is done wrong you may get the hashes, that's what Thomas mentioned, but this is a question of using a good library. The advantage is, that you can exchange the key whenever you have need to, even periodically. Another [discussed](http://stackoverflow.com/a/16896216/575765) point is, that you do not interfere in any way with the hash algorithm. – martinstoeckli Apr 25 '14 at 15:12
  • You right. Using MAC this way is misuse. – Powerman Apr 25 '14 at 20:26
  • Using encryption looks more suitable. Ability to exchange the key is important too. But, in general, I think it will be more secure to prevent users from using simple passwords - because in many cases SQLi in one way or another lead to ability to read files (and thus get pepper and decrypt hashes before bruteforce). So, encryption looks useful only for legacy projects where we already have possibly-simple passwords in db. – Powerman Apr 25 '14 at 20:38
  • @Powerman - It is surely a good idea to ask the users for strong passwords, but unfortunately it's not under your control. The password "Password-2014" will pass most checks, but is not very strong. As for SQLi, SQL-injection can be prevented easily with parametrized queries, only third party libraries are a problem. Reading files from the server with SQL is even much more difficult and works only with certain database configurations, so in my opinion encrypting with a server-side key should be done in any case. – martinstoeckli Apr 26 '14 at 09:46
  • When doing the peppering in a dedicated service/process using a HMAC is easier to proof that the key is kept secret (since that’s the purpose of the HMAC) also some existing services like HSM or TPM or things like HMAC tokens only provide secret key primitives with HMAC. – eckes Aug 09 '18 at 21:46
  • Hi @martinstoeckli, I am thinking about how should I apply the pepper on the server. I saw your answer in SO https://stackoverflow.com/a/16893270/5983841 and also your question here. I have a question : **What's the difference between concatenating the pepper directly and adding an extra hash function?** You said that a pepper is aimed to defense **dictionary attack**, I do agree. But once someone compromises your server, I see no difference with this 3 ways applying a pepper. Can you explain? Thank you – Rick Jul 02 '19 at 08:09
  • @Rick - This is correct, as soon as an attacker gets control over the server, there is no advantage at all, and it makes no difference which method you applied. Though there are many situations where the hashes leak, but the attacker has no control over the server (doesn't know the server side key/pepper), then your hashes cannot be brute-forced. The encryption method has the advantage of beeing able to exchange the key when necessary and is the first choice. – martinstoeckli Jul 02 '19 at 08:37
  • @martinstoeckli OK.. I just want to say that I think concatenating the pepper is already enough, the other 2 are meaningless. Btw, if the server and database both get compromised, it seems that there's no way to prevent dictionary attack, is that right? – Rick Jul 02 '19 at 08:44
  • @Rick - The pepper is of no use then, maybe a HSM module may help in this case. It is easier to make a mistake by just concatenating the pepper, a long pepper at the begin could e.g. cancel out parts of the password, or the pepper could contain null bytes and theoretically truncate the password at all (well the null byte can be a problem for HMAC output too). – martinstoeckli Jul 02 '19 at 09:00

1 Answers1

35

Your three methods are correct. The third (with HMAC) might be a tad more "elegant", mathematically speaking: it would make it easier to prove the security of the construction, relatively to those of bcrypt and HMAC.

Beware, though, of null bytes. A given bcrypt implementation might expect a character string and stop at the first byte of value 0, which may occur in the output of either SHA-256 or HMAC (or as part of the binary key you use as pepper), ignoring all subsequent bytes. It would be a grave problem, and you would not notice it. To avoid that problem, you might want to Base64-encode the SHA-256 or HMAC output before giving it to bcrypt (Base64-encoded SHA-256 output is 44 characters, still below the bcrypt limit).

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • 1
    Thanks a lot for this helpful answer, especially the tip about binary output. So you see no obvious problems with just concatenating password and pepper? – martinstoeckli Oct 07 '12 at 21:10
  • 1
    As long as the pepper is of fixed size (so that it could be unambiguously "removed"), and you do not exceed the 55-character limit, and avoid the troublesome zeros, then concatenation should be fine. – Thomas Pornin Oct 07 '12 at 21:13
  • Given that BCrypt doesn't actually have a "pepper" input, isn't it potentially safer to either encrypt or HMAC the password digest? Peppers feel very much to me like inventing your own crypto. – Stephen Touset Oct 07 '12 at 21:14
  • 3
    bcrypt is meant to tolerate _passwords_ as input. Passwords are about the worst kind of input you can get; I do not see harm coming that way, when adding a MAC. The danger here would be that the addition of the "pepper" induces two distinct passwords to yield the same bcrypt input, e.g. because of an unwanted truncation from a null byte. Apart from that, anything which looks like an injection can be applied to the input of bcrypt as a preparation step (hashing or MACing is injective-like because finding collisions is hard). – Thomas Pornin Oct 07 '12 at 21:20
  • What about applying an HMAC or encrypting the *output*? Although with standard BCrypt libraries, an HMAC might be annoying since they don't typically provide explicit access to the salt and cost factor in the input or output. – Stephen Touset Oct 07 '12 at 21:28
  • You could HMAC the output of bcrypt, taking care of avoiding the salt and cost factor, as you notice -- so that's a bit delicate and could be affected by newer versions of the libraries. As for encryption, it implies the dreaded IV business. I think HMAC on the _input_ (the password) is safer (harder to get wrong). – Thomas Pornin Oct 07 '12 at 21:46
  • If concatenating, place the pepper before the password, as pepper is more predictable in length and character set (no NULs) than the password. – 700 Software Jul 19 '16 at 21:16
  • so keyed password protect from timing attack I guess since the key processing isn't now to the hacker ? – Webwoman Aug 27 '18 at 16:36