Hacker News new | past | comments | ask | show | jobs | submit login

I generally disagree with hardcoded salts, you should assume everything is compromised in a successful attack. But I'm actually commenting here because I don't see how you can retroactively apply the second salt to a hashed string. Could you please elaborate or share a link?

Later edit: I'm referring to your example in your link:

    salt = urandom(16)
    pepper = "oFMLjbFr2Bb3XR)aKKst@kBF}tHD9q"  # or,
    getenv('PEPPER')
    hashed_password = scrypt(password, salt + pepper)
    store(hashed_password, salt)
How do you retroactively apply this?



In incident response you assume the worst, but in system design you try to minimize impact of common attacks like SQL injection.

There's nothing wrong with nesting algorithms (see the Facebook hash onion), so you can use the following scheme:

    bcrypt(bcrypt(password, salt), pepper)
And do a pass on all your database entries like

    bcrypt(old_hash, pepper)


In your website's example, you have

    bcrypt(password, salt+pepper)
Observe the difference between that and the rehash you just posted

    bcrypt(bcrypt(password, salt), pepper)


> bcrypt(password, salt+pepper)

I hope it's obvious that no one should never do this, since the output would contain the "salt+pepper" bits in cleartext alongside the hash, defeating the entire point of the "pepper":

https://www.usenix.org/legacy/event/usenix99/provos/provos_h...

In fact, this is a perfect illustration of why it's bad to put secret bits into a crypto function in a place that's not designed to take secret bits. Bcrypt does not treat the salt parameter as a cryptographic secret, and other algorithms might not either. And they might leak it in more subtle ways.


One would think it's obvious, yet this is what the person in the linked article suggests doing :/


> There's nothing wrong with nesting algorithms

This is really vague. What kind of algorithm? With itself, or just anything inside anything else? Passing the raw output of any common cryptographic hash (SHA-x) to bcrypt, for example, completely destroys its security, as bcrypt input is null-terminated.

(What happens when you nest DES in A*, anyway?)


Obviously you have to use type safety. You can't cast a binary string to a null-terminated string, you have to convert. That's a problem unrelated to hashing.

I would avoid using any particular symmetric algorithm twice. Otherwise if you have an example of algorithm chaining that can weaken security beyond the weakest link, I would love to see it. (Not that I think nesting is a great idea.)


> That's a problem unrelated to hashing.

It (poor implementation) is definitely related to implementing pepper on top of a secure password hash, though, which everybody is already doing differently.

> I would avoid using any particular symmetric algorithm twice. Otherwise if you have an example of algorithm chaining that can weaken security beyond the weakest link, I would love to see it. (Not that I think nesting is a great idea.)

“algorithm” is, again, really vague. (So is “nesting”.) But for something contrived and not snarky, here:

  h = sha512_hex(password)
  sha512_hex(bcrypt(h, gen_salt()) +
             bcrypt(h, gen_salt()) +
             bcrypt(h, gen_salt()) +
             bcrypt(h, gen_salt()))
The weakest link here is 374 bits (4 bcrypts), but the output is 288.


Oh sorry I missed this post for a while.

>“algorithm” is, again, really vague

Something that you can use to hash passwords. What you gave works if you assume gen_salt is seeded per user.

>The weakest link here is 374 bits (4 bcrypts), but the output is 288.

I'm afraid I don't follow. Your bit numbers confuse me, and I don't see how this results in an algorithm that is weaker than either sha512 or bcrypt.


> I'm afraid I don't follow. Your bit numbers confuse me

They’re bits of entropy (not counting the password itself) (I think). SHA-512(M): 512 bits; SHA-512(SHA-256(M)): 256 bits, for example.

> I don't see how this results in an algorithm that is weaker than either sha512 or bcrypt.

That’s my point. It’s not easy to get this kind of thing right, so just don’t bother with pepper.


Bits of entropy I understand, how you got "374" and "288" I don't.

>That’s my point. It’s not easy to get this kind of thing right, so just don’t bother with pepper.

What? Your point is that you haven't demonstrated that it's weaker than the weakest link, therefore you win?

Edit: Okay I figured out where you got 288. Still confused by the 374. Anyway you need to make truncations explicit. You didn't pass all of the sha output to bcrypt. You're taking advantage of an implementation API bug.

I'm not asking for evidence that shoving together functions from google without understanding them can go wrong. That's trivially true.

I want an example where combining hash algorithms is inherently wrong. Like using a block cypher twice can pop out your plaintext, but probably not as extreme.

Edit 2: Oh, 384!


    passwordHash = bcrypt(salt + password)
    encryptedHash = encrypt(passwordHash, pepper)
This way you can rotate your pepper by doing:

    decryptedHash = decrypt(encryptedHash , oldpepper)
    encryptedHash = encrypt(decryptedHash , newpepper)


Excuse my ignorance, but you probably shouldn't be able to reverse an irreversible hash.


The point of hashing passwords is that the true password is not revealable.

The point of salting password hashes is to prevent identical cleartext passwords from being stored as identical hashes in the database. Salts are often stored in the database, as well.

The point of peppering keeps a database dump from being at all useful for recovering passwords. It make sure that a component of the process of cleartext -> DB entry is not even in the database, requiring something from the app as well.

Why does encryption work here? Because you've already done a one way function on the cleartext -> salted hash. At that point, there is still no way to reverse the process all the way to get the cleartext. By using a two-way encryption function for the pepper portion, you keep the ability to rotate 'peppers' periodically, in case it is leaked, for example.


Thanks for the informative post


The pepper is being used as an encryption key in that example rather than using hashing.


In pacofvf's example, you are correct.

But, the original example is hashing the password. No encryption involved. So what makes anyone think that they can reverse a hash?


The problem is that pacofvf's answer assumes you don't need to do this retroactively.

This would work if you were building a new system today, but if you had a DB full of one way hashes you're not going to be able to retroactively modify the pepper.


And more importantly, slack straight up stated they salt the password and use bcrypt. It's all one way hashes, no encrypting/decrypting going on.


It's reversing the encryption, not the hash.


Where in the original example was encryption involved? The salt and pepper were only ever used in a hashing algorithm.


The pepper is the key to the encryption, not a hashing algorithm.


Thanks for just ignoring my question - THERE IS NO ENCRYPTION IN THE ORIGINAL ARTICLE, so WHY are you restating that encryption is involved at all?

Straight from the original artical:

  hashed_password = scrypt(password, salt + pepper)
or

  hashed_password = scrypt(scrypt(password, salt),pepper)
Absolutely zero encryption going on here. Therefore, no ability to "decrypt" the pepper result. The pepper IS NOT a key for encryption. Period.


You append the salt to the hash, and then re-hash it. Not exactly pretty, but it works.


His example doesn't rehash. His example adds the pepper to the initial salt. This is an honest question, how does one apply it retroactively?


I think you are spot on - you can't apply it retroactively in this case. If you set it up as H(H(pwd, salt), pepper), you could apply pepper retroactively, but that's not what's proposed here nor in the SO question linked above. Also if you do H(H(pwd, salt), pepper), you can successively apply new peppers and make it a bit more maintainable, but I am unclear that it is secure to do so.


Update the hash when the user logs in because you have the password. You can tell if it's been applied by having another column, or prepending/suffixing the output with something that scrypt can't output.


I don't understand your issue with hardcoded salts. It essentially works the same way as an HMAC. It is some secret material that further complicates the attackers job...It doesn't mean they react to a successful attack in a different way.

After hashing the password he is storing the hash along with the users random salt, not retroactively applying the salt a second time.


Your question depends on your definition of retroactively.

I think the article's context is if you don't currently use a pepper, you can easily add one and update all of your password hashes in the database.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: