
Enough with the Salts: Updates on Secure Password Schemes - saturdayplace
http://chargen.matasano.com/chargen/2015/3/26/enough-with-the-salts-updates-on-secure-password-schemes.html
======
moxie
It's easy to say "use bcrypt" or "use scrypt," but I think it's important to
acknowledge the challenges of deploying those functions in large scale high
performance environments.

It's straightforward and effective when password hashing happens client-side
(like local encryption for a bitcoin wallet), but using scrypt or bcrypt
_server-side_ at effective difficulty levels will either destroy your L1/L2
cache or exceed your CPU budget.

In practice, from what I've seen, this means scrypt is never used, and bcrypt
is used with a work factor that's tuned low. I think this is just a
fundamental asymmetry, and that at the end of the day people use bcrypt so
that they can say "we used bcrypt!" and get a nod when their entire user
database is compromised, even though it provides very little value the way
it's deployed.

~~~
mrb
> I think this is just a fundamental asymmetry

Actually the Password Hashing Competition has shown this asymmetry can be
exploited to the server's advantage: one of the ideas being studied is called
_server relief_.

For example instead of storing the scrypt hash on the server you store the
SHA256 hash of the scrypt hash (and the salt alongside), and ask the client to
send the scrypt hash to authenticate. This way the per authentication cost to
the client is expensive (one scrypt hash) but the cost to the server is cheap
(only one SHA256 hash).

Attackers cannot take shortcuts. They cannot send random scrypt hashes to the
server while skipping the scrypt computation step, because the space of
possible scrypt hashes is just too large to brute force.

The only downside of server relief is that you need custom code on the client-
side to do the computation. So it works with javascript in browsers, but not
with traditional clients like an IMAP or POP3 mail app.

Edit: @__david__: yes you could SHA256() only the hash part of the scrypt
hash, as opposed to the hash & salt parts. It is an implementation detail
--not really important. And regardless of how you do it, if the DB get stolen
the SHA256 hashes are useless to authenticate.

Edit: @espadrine: no, breaking a SHA256(scrypt()) hash is no easier than
breaking a scrypt() hash. Server relief with SHA256 introduces no weaknesses.
It is strictly more secure than standard scrypt hashes.

Edit: @plantbased: I recommend against MD5(scrypt()), because it is likely
preimage attacks will be found on MD5 in the near future, so someone stealing
your database of MD5(scrypt()) hashes will be capable of computing an
arbitrary scrypt hash that authenticates to a given user. But you could
certainly do MD5-crypt(scrypt()) with MD5-crypt being the salted & iterated
version by PHK.

~~~
espadrine
> The only downside of server relief is that you need custom code on the
> client-side

That, and the major reason we do hashes even over TLS: if the server gets
cracked and the attacker has access to the stored hashes, breaking a SHA256 is
trivial (ie, brute-forcing b when knowing s = SHA256(b)). Then, the attacker
can assume the identity of any individual whose SHA256 s got broken, by
sending the bcrypt b directly from a crafted client, without having to find p
where b = bcrypt(p).

~~~
emn13
People have odd ideas about how serious the vulnerabilities in hashes are.
These hashes, even old and obsolete ones, are still entirely secure for
password like hashing _if the password is random enough_ , which scrypt output
is.

Even MD5 is still (AFAIK) effectively unbreakable in this use case (finding
md5 collisions is possible, finding the input given an md5 is not). According
to
[http://en.wikipedia.org/wiki/MD5#Preimage_vulnerability](http://en.wikipedia.org/wiki/MD5#Preimage_vulnerability)
finding input to generate a given md5 has a complexity of 2^123.4 - i.e. never
going to happen. And that's Md5, an obsolete hash!

Sha1, also considered obsolete, has a bad rep because there are scary
theoretical collision attacks. This isn't good news, certainly, but for a
sense of perspective: nobody, not even with lots of distributed computing
power, has ever actually managed to find a collision since that would take
_around_ 2^60 attempts. I don't think anyone has ever found even a theoretical
weakness in its preimage resistance.

And you're talking about sha2 - there have been no published reports on any
attacks, even theoretical, on the full sha2 (they have found weaknesses on
reduced versions, suggesting room for improvement - but that's largely of
academic interest).

Collision attacks are another matter. If you're using a hash to _sign_
potentially hostile content rather than recognize friendly content, md5 is
clearly dangerous, and sha1 may well become so. But that's relevant to things
like certificate authorities, not message authentication.

~~~
vectorjohn
If collisions are not too hard to find, isn't the process just:

1: Steal database 2: find collision 3: authenticate with the input that hashes
to the same value

What stops that from happening?

~~~
vectorjohn
@teraflop - Oh, so does that just mean basically that you can, e.g. generate a
bunch of MD5 hashes and some will be the same? But if you have a target you're
basically SOL finding a collision for that? That would make sense if that's
what it means.

~~~
teraflop
Yep.

More specifically: if you just hash a bunch of arbitrary strings that aren't
specially-constructed for the purpose of colliding, then collisions are
basically random, and extremely improbable. But you can fairly easily generate
two files, differing only in a small number of bits, with the same MD5 hash by
taking advantage of the structure of the algorithm.

Examples here:
[http://www.mscs.dal.ca/~selinger/md5collision/](http://www.mscs.dal.ca/~selinger/md5collision/)

~~~
emn13
Another consequence of that is that _even_ MD5 collisions aren't at all
trivial to exploit in general. An attacker can create _a_ collision, but it's
a slow process, and the colliding content is pretty constrained. You'd
probably need to be very well informed, and invest quite some creativity to
find two messages that are "valid" to whatever system is processing those and
have sufficiently different meanings to be useful to you.

Clearly doable in specific instances, but it's not going to be an addition to
the script-kiddie attack handbook anytime soon.

------
ryan-c
This article says salting hashes is only useful against rainbow tables. That
does not make sense to me. Say you have a password database with 10,000 users
in it. You want to see if any of them used "Passw0rd$". Without salt, you
compute the hash once and check it against _all_ the users (perhaps with a
bloom filter). With per-user salts, you have to compute the hash for _each
user_.

I think salting offers pretty clear benefits against other attacks if you have
more than one user.

Edit: The point I'm trying to make here is that it is N_USERS times better to
have a unique salt per user, regardless of the hash. One should use
bcrypt/scrypt/pbkdf2 with unique per-user salts.

~~~
kasey_junk
The salt is typically assumed to not be secret. With modern hardware
recalculating the hash is not hard for "fast" hashes, regardless of salting.
That's why choosing a slow hash is more important for this vector of attack
than anything else.

Of course salting is better than no salting, but its orders of magnitude less
important than choosing a good hashing mechanism. Luckily, the _good_ hashing
mechanisms do the salting for you so fixating on salting really just serves as
a proxy for letting us know that you don't understand the attack vector.

~~~
GhotiFish
forgive me, I haven't worked with a good hashing mechanism before.

How can it "salt for you" without you providing the salt?

This question is operating on the presumption of a unique salt per user.

~~~
kasey_junk
I was skipping some complexity. Something like b/scrypt are more than _just_
hashing. They are key derivation functions, which look similar to hash
functions on their inputs.

bcrypt for instance generates a random salt on the input and stores it in the
output.

[http://stackoverflow.com/questions/6832445/how-can-bcrypt-
ha...](http://stackoverflow.com/questions/6832445/how-can-bcrypt-have-built-
in-salts)

------
femto113
> I see the mantra ‘salt your password hashes!’ > repeated over and over, when
> its only real > value is against rainbow tables

This is dangerously incomplete reasoning. Salts real value is that if multiple
password hashes are Leaked simultaneously then each must be cracked
individually. In the Adobe leak password hints were included, which allowed
for very easy guessing of passwords, and because there were no salts even if
you had no hint if someone else had the same password and an obvious hint you
were cracked.

~~~
worklogin
I was about to make the same post.

If a database is popped and people know John123's password, and his hash is
the same as Worklogin456's hash, then they know my password.

~~~
nopar8
I am extremely ignorant about this topic. But I don't think that's how it
works. Can someone else weigh in please.

~~~
cheapsteak
unsalted:

username | sha256 hash john123 |
ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f joe456 |
ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f

salted:

username | salt | sha256 hash john123 | ponies |
98d4c01710b2b775e41b0bf4984f0cec7621ae1dfc4304047b196af46ed589b2 joe456 |
beards | 0f7c74279db5daa1f4de41cc7f6acc94651da754c41675dcde8dcf151d14f5bf

their passwords are all `password123`

------
mdavidn
Salt has one other important property: Salt makes grouping users by password
more difficult.

Some subset of your users will inevitably use the same terrible password as
another user. Or one user will create multiple accounts using the same strong
password. These passwords should appear unique in storage.

You still need salt, and that salt must be unique for each password. That's
the peril of PBKDF2 password storage: I've seen applications completely botch
salting by using one for all users. Bcrypt and scrypt avoid this common error
by salting internally.

~~~
shadowfiend
Computing the hash of a known password is trivial, though—once you know one
user used Passw0rd$, it's easy to check every user for that password, even if
you have a salt, because the salt is not hidden. So you're just running n
password checks in the number of users—admittedly, this is still n checks, but
the difficulty of that pales in comparison to brute forcing passwords, and
while it's strictly slower than just checking “is anyone else using exactly
this”, it's not that much slower in the larger scheme of breaking a set of
passwords.

At least that's my understanding... I am not a security expert! :)

~~~
icebraining
Checking every user for a specific password is equivalent to a dictionary
attack, using a single word. In fact, commonly found passwords from previous
leaks are usually incorporated in such dictionaries.

------
djb_hackernews
I'd be interested to hear more about the approaches a hacker would take in
each case if they came across the hashed passwords and have no knowledge of
the salts, etc.

For instance in the first case where hash = md5('deliciously-salty-' \+
password)

I'm not sure how easy it is for an attacker to reverse the hash if they don't
know the salt. (I understand you need to assume the attacker has the salt, but
just posing a constrained hypothetical here)

~~~
icebraining
It's equivalent of attacking md5('deliciously-salty-'), since the password can
be known, e.g., by using the hash from their own account.

Attacking md5 is not really that hard, nowadays - the article mentions 180
_billion_ tries/second.

Yes, it requires a rig with 25 GPUs, but this is almost the perfect use for
the "cloud" \- you can rent those for a few bucks just for a specific attack.
There are even dedicated services nowadays, with no programming knowledge
required - you just submit the hashes, and out come the found passwords.

~~~
djb_hackernews
Hmm I still don't understand, but thanks for replying to my (downvoted) honest
question.

If all you have is a hash and know the password you still dont know if it's

md5sum('salt:' \+ password) or

md5sum(password + '-salt') or

md5sum('salt+' \+ password + '=salt')

etc

I suppose you'd need to brute force a large key space and look for any results
which contain your known password. Does that sound right?

~~~
nathanaldensr
That's true, but once you discover the salt pattern used, then you can crack a
specific password and look for the resultant hash in the database. The idea is
to use a random salt per password to close this attack vector. That way, even
if you do guess the password and you have the salt, the resultant hash is only
useful for that one password, even if the same clear-text password is used in
other hashes.

Think about it: adding a known global salt to each password in the same manner
before hashing is effectively the same (in the long run) as not salting. Once
the attacker figures out the pattern you used, he can proceed to crack
specific passwords, then search for the resultant hashes in the database.

~~~
geoelectric
What I don't understand (truly--I'm a curious neophyte here) is why a random
number would be better than salting with, say, their username.

If the assumption is that the random number is known, per both guidelines that
only the user-given secret can be assumed secret and that the article says it
could conceivably be stored plaintext, isn't it effectively equivalent to just
another username?

~~~
icebraining
You can, but it prevents you from allowing changing the username (which might
be fine, but why tie yourself?) and it provides less entropy - a username +
password can be small enough to fit in a rainbow table, while a random salt
can have whatever size you want.

~~~
nathanaldensr
Excellent explanation. I'll further this by adding that, in my use of the
excellent PBKDF2.NET library, I generate a salt with the same number of bits
that the hashing algorithm generates (e.g., 256-bit salt for SHA256). I can't
remember where I read that this was a good practice, though. :(

------
pstrateman
"The value of salts is limited to thwarting attacks leveraged pre calculated
lookup tables such as rainbow tables."

This is absolute drivel.

Salts prevent checking an attempt against all the hashes in parallel.

That is to say if the attacker has a dump of 1 million salted hashes, they
have 1 million times the work to do compared to 1 million unsalted hashes.

~~~
unreal37
I am also suspicious of the claim that a fixed salt+password hash scheme is
"just as insecure" as a no-salt password hash scheme. The salt (unknown to the
attacker) has to add at least a few order of magnitudes more security just by
turning "password123" into "somesalt65634734password123" right?

Just from the added password length alone it has to be "way more" secure,
right? Would love some professional crypto opinion on this.

~~~
minitech
> The salt (unknown to the attacker)

The salt is generally known to the attacker. The point of the salt is that
it’s unique for each password hash, making it impossible to run crack attempts
on every password at the same time; for a password hash to be checked, the
salt has to be retrieved. This means they’re usually stored together and
therefore also compromised together; keeping them apart is rarely useful (kind
of like peppers, which is what you might be thinking of; they’re per-
application rather than per-hash, and their purpose is to be unknown to the
attacker, which is equivalent to encrypting things with a per-application
key).

------
nmc
Found the _" unnamed blog"_ post giving the _" terrible"_ salting advice:
[http://blog.codinghorror.com/rainbow-hash-
cracking/](http://blog.codinghorror.com/rainbow-hash-cracking/)

~~~
xxxyy
The title seems to be misleading. Nowhere in the article does the author
explicitly state that salts should not be used, because well, they should be
used. His point was that salts are not enough, you need to couple them with a
possibly slowest, yet acceptable hash function. And then hope that Moore's law
does not breach your passwords.

~~~
MichaelGG
Yes. But he's also pointing out tons of the advice given, perhaps by people
that are well-known and respected-by-some, is just wrong.

Iterative hashing with per-user salts has been a known pattern. Practical
Cryptography covered it in the first edition. The relevant parts should be
derivable for most engineers. There's no reason there should be any confusion
or crazy blog posts.

------
btilly
The need for unique passwords brings me to a stupid idea that I've had for a
while.

Imagine a service which just stores hashes of every password that it can find
from everywhere. Any site that wants can check whether a given password is in
use..somewhere..and reject it if it is. Any site that wants can add more
passwords to the list.

Internally the service would work from a bloom table designed for a fixed
false positive rate. (You can actually layer bloom tables in front of bloom
tables with parameters to make this possible.) So even if someone compromises
that site, there is no direct record of the actual hashes for passwords.

Basically let sites say, "You have to choose a unique password, and do not
reuse a password that anyone has used elsewhere!"

~~~
sarciszewski
This would only work if you could achieve this search with the use of a zero-
knowledge proof. Actually disclosing your password to the service would defeat
the point.

~~~
btilly
Yes, this is a weakness. The password would need to be disclosed in the form
of a hash of the password, and the hash algorithm has to match what everyone
else does.

If the service and your site were _both_ compromised, then it would be
possible to match up incoming hashed passwords to users by timestamp. But even
so, the fact that no passwords were reused will hopefully make cracking the
hashes harder.

So..probably a bad idea. :-(

------
sarciszewski
I've been saying "scrypt, bcrypt, PBKDF2, or bust" for years.

Also, there's a large industry trend of, "let's 'pepper' our hashes too!"
whereby they have a sitewide salt. This is a mistake. If you want to add a
site-specific layer of security to your passwords, encrypting them makes far
better sense than adding to the salt.

[https://github.com/lizardhq/php_bcrypt_aes](https://github.com/lizardhq/php_bcrypt_aes)

[http://blog.ircmaxell.com/2015/03/security-issue-
combining-b...](http://blog.ircmaxell.com/2015/03/security-issue-combining-
bcrypt-with.html)

------
noinsight
It's not just the scheme that's important, it's also the implementation of it
that's important. If I'm doing the smart thing and not rolling my own crypto,
can I trust the existing implementation that I've chosen? It's hard to say.
Does it have secure defaults or do I need to choose and why do I need to
choose, why aren't the defaults secure? I'm not a crypto expert, I'm not
qualified to judge and therefore I don't even care (as such) - why aren't the
defaults secure?

For example, I'm writing an app that requires a password setup in Python so I
was investigating this issue:

1\. Passlib -
[https://pythonhosted.org/passlib/](https://pythonhosted.org/passlib/) \-
"implementations of over 30 password hashing algorithms" \- What? I'm not
qualified to judge what's secure so I don't even care, I just want something
secure!

2\. python bcrypt -
[https://pypi.python.org/pypi/bcrypt/1.0.1](https://pypi.python.org/pypi/bcrypt/1.0.1)
\- OK standard bcrypt, supposedly that's secure - "Author: Donald Stufft" \-
who is Donald Stufft? Is the code good? I don't know C and I'm not qualified
to judge!

3\. python scrypt -
[https://pypi.python.org/pypi/scrypt/](https://pypi.python.org/pypi/scrypt/)
\- OK it's Colin Percival's code, it's probably good, "Author: Magnus Hallin"
\- did Magnus Hallin screw it up though? "Burstaholic on Bitbucket provided
the necessary changes to make the library build on Windows." Eh. Did
"Burstaholic" ruin the crypto? Who knows.

Also, in my case I needed something cross-platform, primarily for Windows.
bcrypt worked out of the box. The scrypt library required building on Windows
with OpenSSL development headers or whatever and all that - I just said
"pass".

Nacl is fantastic and simple to use, it can't get much easier than this:
[https://libnacl.readthedocs.org/en/latest/topics/public.html](https://libnacl.readthedocs.org/en/latest/topics/public.html)

Something similar should exist for passwords - I just want to call
compare(password, storedhash) or whatever and be done with it, I'm not
qualified to judge the crypto. And it should be cross-platform.

~~~
im3w1l
This is why I love the (modern) php approach. It's in the standard library and
you don't need to supply an algorithm name or salt or anything. It is also
designed so that a future version of php can have upgraded algorithms without
breaking current code. It is trivially easy to write code that upgrades old
hashes when the user logins in.

[http://php.net/manual/en/function.password-needs-
rehash.php](http://php.net/manual/en/function.password-needs-rehash.php)

------
hueving
This is missing something pretty important about salts. They hide the fact
that two users have the same password. That's a huge security risk if that
correlation is leaked.

Correct me if this is mentioned in the article, but based on several mentions
of how salts were effectively useless, I think this was overlooked.

~~~
homulilly
I didn't get the impression the author was saying salts are useless, obviously
you still have to use them and bcrypt and scrypt both do. The point is that a
lot of programmers naively assume that a salt (or salt+pepper) will make their
password storage secure on its own when that isn't really true anymore.

------
tootie
I fail to understand why salting is bad. Seems like he's saying it's not a
cureall. We knew that. But it's at least marginally better than not salting
and it's easy, so why the hell not?

~~~
amouat
Yeah, salting definitely isn't bad, in fact it's actually essential. What the
author is saying is that it's not enough - salting won't save you when your
attacker can test 10s or 100s of thousands of hashes a sec. The article could
have been phrased better.

------
slasaus
I've recently found out about Diceware and the importance of a strong password
[1][2]. Often users choose a really weak password to begin with. I've read [3]
that if you have a strong password (like a 7 word Diceware password) even MD4
or MD5 would suffice :O. I'm really curious if this is true.

[1]
[http://world.std.com/~reinhold/diceware.html](http://world.std.com/~reinhold/diceware.html)

[2] [https://firstlook.org/theintercept/2015/03/26/passphrases-
ca...](https://firstlook.org/theintercept/2015/03/26/passphrases-can-memorize-
attackers-cant-guess/)

[3]
[https://github.com/freedomofpress/securedrop/issues/180#issu...](https://github.com/freedomofpress/securedrop/issues/180#issuecomment-29760395)

ps. for those that use bcrypt and want to ensure a constant user experience on
their server see [https://www.npmjs.com/package/bcrypt-
speed](https://www.npmjs.com/package/bcrypt-speed)

------
zobzu
while we're at it and throwing stuff around as if its an easy fix: lets stop
using passwords. Use keys. Use a trust model on these keys. So many
advantages.. you don't receive the cleartext password no more (because really
I DONT CARE if you use triplezscrypt.. SINCE YOU GET MY PASSWORD IN CLEAR TEXT
during authentication.. its not like if compromises were "on the database".
Its always at the application level.)

Beside it makes rotation easier, and not having to remember multiple
passwords, or having a password manager, etc. a thing.

Oh wait ;) Google and others are actually attempting to make this work with
U2F:

[https://support.google.com/accounts/answer/6103523?hl=en](https://support.google.com/accounts/answer/6103523?hl=en)
(yes it works with gmail. Right. Now.)

[https://www.yubico.com/applications/fido/](https://www.yubico.com/applications/fido/)

------
biot
The points made here are covered in Coda Hale's post:
[http://codahale.com/how-to-safely-store-a-password/](http://codahale.com/how-
to-safely-store-a-password/)

While it recommends using bcrypt, if you augment that with "or scrypt or
PBKDF2" the same principles apply.

------
danbruc
There is one thing that I think is often omitted. A _lot_ of user use trivial
passwords and they reuse them. These users' passwords will fall essentially no
matter what you do because making the check so slow that a dictionary attack
with a couple thousand very common passwords becomes impractical is itself
borderline impractical. On the other hand strong passwords will withstand an
attack even if they are hashed with plain MD5 or SHA1 - at least right now,
there are already some serious collision attacks.

The user group really benefiting from strong password hashing schemes is the
one between the two mentioned extremes. So if you really want to protect all
your users and use simple password authentication you have to enforce strong
passwords policies which is itself not trivial and will definitely badly annoy
some users.

~~~
jjarmoc
> There is one thing that I think is often omitted. A lot of user use trivial
> passwords and they reuse them. These users' passwords will fall essentially
> no matter what you do because making the check so slow that a dictionary
> attack with a couple thousand very common passwords becomes impractical is
> itself borderline impractical.

Sure. This is something I touched on very briefly near the end of the post.
Password re-use is a huge problem and could easily be an blogpost of its own.

> On the other hand strong passwords will withstand an attack even if they are
> hashed with plain MD5 or SHA1 - at least right now, there are already some
> serious collision attacks.

For some value of 'strong' sure. If you're password is long enough, random
enough, and of a broad character set then yes, an md5() of that may well be
beyond the reach of most attackers. But that's not the sort of password most
people, even security conscious people, choose. A preimage against MD5 would
quickly change this too, and that's a risky gamble.

> The user group really benefiting from strong password hashing schemes is the
> one between the two mentioned extremes.

The best we can do is make attacker costs a function of the password that the
user has chosen. If someone makes their password 'password' there's no degree
of magic that's going to help. Mostly, the benefit comes if/when disclosure
occurs and there's an active incident response effort.

> So if you really want to protect all your users and use simple password
> authentication you have to enforce strong passwords policies which is itself
> not trivial and will definitely badly annoy some users.

It's not a zero sum game. When a breach occurs, the rough points in time are
something like:

1) Attacker compromises digests (let's just assume all are obtained in an
instant, rather than exfiltrated over time) 2) Attacker recovers 1 password 3)
Attacker recovers n passwords 4) Attacker recovers all passwords

Our goal isn't to eliminate these steps except hopefully the extreme of 4.
Rather, it's to increase the time between 2 and 4, and make sure 3 is closer
to 2 than 4.

On the other side of the coin, there's a few points in time:

a) Victim org. realizes digests have been compromised. b) Some credentials
valid at 1 are made invalid. c) All credentials valid at 1 are made invalid.

If you accept my previous point that at some extreme there's nothing that can
be done to prevent brute force, then you should also see that storing
passwords in this fashion isn't meant to be a perfect defense. By minimizing
the number of compromised accounts at a given point in time, we can maximize
the benefits of our response. We can notify users and force resets,
invalidating some set of credentials before they're recovered. We want b and c
to be closer in time to 2 than 4, and minimize the value of n when we get
there.

------
elchief
Since the author didn't bother to mention any threat models, we can assume
that the threat is the most common one, SQL Injection.

You don't need SQL Injection if you can directly read the database file, or
can operate as the web server user, therefore if you're doing SQL Injection
you don't have those privileges.

If you can HMAC or encrypt passwords (prior to hashing them) in the database
with a key only on the web server, then that's an extra level of protection.
You can't get that key with SQL Injection alone.

[https://blog.mozilla.org/webdev/2012/06/08/lets-talk-
about-p...](https://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-
password-storage/)

password_hash(base64_encode(hash_hmac("sha512", $password, $key, true)),
PASSWORD_BCRYPT)

~~~
ajanuary
> we can assume that the threat is the most common one

No we can't.

------
Sami_Lehtinen
How about not reusing passwords and always using a strong password? SHA256
alone is enough, when you just do that. And so what if someone got my
password. If they had already access to the system, they could have also
stolen the data they were after anyway. Today's password: .P`éA@O?/^2HNVSé%@ÖY
it contains more than 256 bits of entropy. Based on this SHA256 collision
attacks and cracking AES128 should be trivial. I personally consider passwords
to be unique shared secret blobs / service.

------
kpcyrd
Password hashing is crypto, too. Don't roll your own crypto.

~~~
sarciszewski
I agree with this advice, even though I'm probably the worst offender. I have:

    
    
        - Rolled my own password library (linked elsewhere in this thread)
        - Rewritten an existing AES-CBC + HMAC-SHA-256 library to use a different 
          underlying driver (mcrypt is basically a mummy at this point)
        - Did both of these things in PHP, which a lot of people assume
          is inherently incompatible with security
    

However, everything I've done in this vein has been passed before people who
are far smarter than myself, to which I received no complaints. And I
constantly seek out criticism from people who understand crypto too. (Aside:
Most crypto people are dicks. But they mean well.)

~~~
ZoFreX
One question: _Why?_

However many people have reviewed your code, far more people have reviewed
libraries like bcrypt!

~~~
sarciszewski
My code _uses_ bcrypt. It's a wrapper around password_hash() and it also
passes it through an authenticated encryption library.

When I said I wrote my own crypto code, I don't mean like something that
belonged in a PHC entry.

------
borski
Jeff's and Thomas' posts are totally on the money. We wrote a piece as well,
specifically to talk about how encryption and hashing are not the same thing.
You'd be surprised how often people screw that up.

[https://www.tinfoilsecurity.com/blog/store-data-securely-
enc...](https://www.tinfoilsecurity.com/blog/store-data-securely-encryption-
hashing-how-to-guide)

------
DenisM
If you are using .NET, you will be glad to know that .NET framework has a
standard implementation of PBKDF2, one of the recommended choices in the
article.

    
    
      var hash = new System.Security.Cryptography.Rfc2898DeriveBytes(password,
        salt, workfactor).GetBytes(32);
    

Using a NIST-approved function that's continuously supported by a large player
seems like a good choice.

~~~
jameshart
The implementation iterates HMACSHA1, which is fine, of course, but which
raised concerns on at least one audit I went through because, well, why would
anybody want to use SHA1 when SHA2 exists?

Wound up having to implement my own version of PBKDF2 that lets you specify
the HMAC algorithm.

------
ghshephard
And, as always - these discussions about Salts/bcrypt/scrypt are only relevant
to people where passwords/security are important, but not critical.

For anybody who has critical security needs, just use an HSM already.
Sophos/Utimaco makes a nice one, and it is a nice foundation for password
security.

------
seanwilson
How about using a tested login library instead and consider using OAuth as
well (e.g. Google account to login)?

Rolling your own login system, dealing with hash functions and checking
passwords yourself is far too low level and dangerous for most apps (as this
thread demonstrates).

------
kyberias
Urghh... I hate these articles that list bad examples of salt use and then
doesn't explain the reasoning why exactly these are bad. Just trying to prove
to the world how smart the author is. Maybe he doesn't really know how to
explain it?

------
k__
Does this mean we should drop the salts, simply scrypt and be done with it?

Or should we still include salts in addition to scrypt?

If yes, only one global or many user specific or both?

------
codahale
Use bcry—ah, fuck it.

------
xai3luGi
Why are we still using passwords in 2015?

