
Don’t Hash Secrets (2008) - pizza
http://benlog.com/articles/2008/06/19/dont-hash-secrets/
======
gohrt
> In fact, I use HMAC for my password databases, too. It’s overkill, but it
> lets me use a standard library that likely makes me safer in the long run.

Actually, it's underkill. HMAC is too easy to crack to be used as a password
hashing scheme.

[http://security.stackexchange.com/questions/16809/is-a-
hmac-...](http://security.stackexchange.com/questions/16809/is-a-hmac-ed-
password-is-more-secure-than-a-bcrypt-ed-or-scrypt-ed-password)

[http://security.stackexchange.com/questions/3165/hmac-why-
no...](http://security.stackexchange.com/questions/3165/hmac-why-not-hmac-for-
password-storage)

------
tptacek
Fun fact: it was a design goal of the SHA-3 competition not to have the hash
be vulnerable to length extension attacks, which obviates the need for
constructions like HMAC that apply the hash function twice.

~~~
oconnore
Sufficiently truncated hashes (SHA-384, SHA-512/256, SHA-512/224) in the SHA2
family should have the same property, right? You need the missing state to
extend.

~~~
JoachimSchipper
Yes, but that's a hack, and not nearly as well-studied as HMAC or SHA-3. If
you decide to do it this way, at least be sure to make it very obvious that
"upgrading" to SHA-512 completely breaks your cryptosystem.

~~~
pbsd
It is fairly well-studied; it's called chopMD in the literature. It has been
shown to be indifferentiable from a random oracle [1, Theorem 3], provided
enough bits are chopped.

[1]
[http://www.cs.nyu.edu/~puniya/papers/merkle.pdf](http://www.cs.nyu.edu/~puniya/papers/merkle.pdf)

~~~
JoachimSchipper
Thanks for pointing me at those papers! I'll admit it's been studied more than
I thought.

(I was actually more worried about cryptanalytic attacks - the construction
itself is obviously secure when instantiated with a random oracle - but I
don't really see how that would work either. I maintain that it's ugly, but
HMAC isn't the nicest construction in the world either, I suppose...)

~~~
pbsd
I suppose there is some CYA value in HMAC, since there is less attacker
control over what goes in the outer hash. If the case is that prefix-MAC (with
chopMD) is vulnerable to some kind of cryptanalysis and HMAC is not, however,
the hash should be considered broken, and not in the academic sense.

~~~
JoachimSchipper
You're completely right, but it's not like people have transitioned off of
SHA-1 (Wikipedia: "As of 2012, the most efficient attack against SHA-1 is
considered to be the one by Marc Stevens with an estimated cost of $2.77M to
break a single hash value by renting CPU power from cloud servers"; note that
renting cloud server time is not a sensible way to approach this problem). Or
even MD5.

------
lmm
Not a very helpful way to express the advice; if you tell people "don't hash
secrets" the natural interpretation is "send them in the clear".

HMACs have their use case, and it's good to use them for that, but honestly
it's a tiny corner of the possibilities for "hashing secrets", and an
effective approximation (hash(message + hash(secret)), as mentioned towards
the end of the article) is the obvious approach if you have any idea how
hashes work, and just as effective as a dedicated HMAC.

~~~
Skalman
I think the point is that that is _not_ necessarily true for all hash
functions, since reordering your example with SHA1 renders it weaker.

If I understood correctly _sha1(sha1(secret) + message)_ is _not_ safe,
because from that hash you can calculate _sha1(sha1(secret) + message +
ANYTHING)_

~~~
Mindless2112
So why not _sha1(sha1(secret) + sha1(message))_? Or is that essentially an
MAC?

~~~
StavrosK
One rule of thumb I've discovered: Whenever you say "why not X?", where "X" is
some nonstandard construction, the answer is "because X is horribly broken in
ways you can't even imagine".

------
bjt
This article is right for the case of using HMACs for two parties checking the
authenticity of a message passed between them (assuming they have a shared
secret).

But it's wrong about the database password storage. These days the real threat
there is the monstrous computing power available to compute tons of hashes
simultaneously. To combat that, you want a hashing function specifically
designed to be _slow_. And not just slow, but to have a tunable parameter so
you can require more and more work as GPUs get faster and cheaper. PBKDF2 is
such a function, and is used by Django as of a year or two ago. bcrypt is
another.

~~~
ukd1
This. Use bcrypt or scrypt for storing secrets. HMAC is for...hash(ing)
message authentication code(s); read:
[http://security.stackexchange.com/questions/16809/is-a-
hmac-...](http://security.stackexchange.com/questions/16809/is-a-hmac-ed-
password-is-more-secure-than-a-bcrypt-ed-or-scrypt-ed-password)

------
rpearl
Say it with me one more time: do not use fast hash functions for passwords.

------
StavrosK
Okay, not to put anyone off crypto, as it's really really important, but the
one rule everyone needs to remember: Use the current best practices for each
situation, don't make up your own crypto.

This usually means "use whatever is in OpenSSL, Keyczar, etc", that's what
it's for.

~~~
mikegagnon
The article makes the point that it is insufficient to use good crypto
algorithms / implementations. You must also use it correctly.

"A component can only be secure under certain well-defined circumstances, not
for any use that happens to look similar."

~~~
StavrosK
A hash is a crypto primitive, it's not what you use for that. If you want to
store a password, you use a KDF. If you want to fake-sign, you use an HMAC
with a secret. You don't use a hash, just like you don't use plain AES to
encrypt a file.

~~~
finnw
> _don 't use plain AES to encrypt a file_

What does "plain" mean in this context? (If you mean ECB then you are right,
but it is ambiguous.)

~~~
StavrosK
I mean a mode without authenticated encryption:

[http://en.wikipedia.org/wiki/Authenticated_encryption](http://en.wikipedia.org/wiki/Authenticated_encryption)

------
theboss
But he is hashing secrets. Salted and Hashed passwords are extremely
important...and saying "Don't Hash Secrets" is just an attempt to get him more
traffic.

There is another important aspect to salting that he neglects to say. Adding
an 8byte salt is extremely effective (along with a proper password hashing
algorithm) in increasing the complexity of generating and storing rainbow
tables. PBKDF2 and bcrypt are both slow enough to protect a lot of that low
hanging fruit that he is saying ISN'T protected....Sure if you use
SHA1....they might get some of them....but everyone agrees you should not be
using SHA1 ! (for passwords).

------
Myrmornis
OK I have a probably naive cryptography question. It seems that one good way
of transmitting secrets would be to do so with everyone thinking they are
encrypted one way (or possibly not at all) when the truth is they are
encrypted another way. I.e. a difficult problem to know when the message has
been unencrypted. So basically there would be multiple ways to read the
message which are plausible as the true unencrypted message. Is there any
parallel to that sort of thing in modern cryptography?

------
maaku
> Here’s the deal: if I tell you that SHA1(foo) is X, then it turns out, in a
> lot of cases, to be quite easy for you to determine what SHA1(foo || bar)
> is. You don’t need to know what foo is. It’s just that, because SHA1 is
> iterative and works block by block, if you know the hash of foo, then you
> can extend the computation to determine the hash of foo || bar.

This is simply wrong. Padding of cryptographic hash functions protect against
this behavior.

~~~
pbsd
It is not simply wrong. The usual Merkle-Damgard padding only means that you
get something like SHA1(foo || garbage || bar) instead, garbage being smaller
than the hash's block size.

~~~
maaku
Maybe disingenuous was a better word. The "garbage" in the middle still
protects against most (though not all) attacks.

------
kGrange
On salting, the author says that an attacker needs to rebuild the dictionary
for each user they attack.

But doesn't the attacker only need to rebuild the dictionary once, using the
salt they recovered?

~~~
fywacro
The salt is different for EVERY secret. When you hash/store a new password,
you randomly generate a salt for THAT password, and you store each salt &
password together.

Because each salt is ~unique, the attacker must rebuild a separate dictionary
for every single stored secret. That's functionally the same as having no
dictionary, at all.

