

Ask YC Crypto Experts: Best ways to store passwords on disk? - cryptonewbie

This is probably an elementary question, but I've had trouble finding the answer, and I know there are some really smart crypto people who post here.<p>I'm trying to store website user passwords on disk securely. I have read some stuff on crypto, but most of it was fairly low-level, dealing with primitive algorithms, not higher-level protocols. I tried to come up with my own protocol, one that would use two hash functions (SHA-256 and something else). It would take the user's password, a random salt (unique to each user) and a nonce (the user ID), and then concatenate them together and hash them. Then with the second hash function, either<p>a) hash the digest obtained from the first function and store the result in the DB, or<p>b) hash the password, salt and nonce again, and store both digests, the one resulting from the first function and the one from second, together in the DB.<p>I am also curious about key stretching/strengthening, and whether it could add anything.<p>Would it better to skip all of this and use something like bcrypt or PBKDF2 instead?
======
cperciva
_Or would it better to use bcrypt or something like PBKDF2?_

If you're going to use either, use scrypt. However...

 _I tried to come up with my own protocol_

...this is a bad idea unless you know what you're doing, and...

 _one that would use two hash functions (SHA-256 and something else). It would
take the password, a random salt for each user and a nonce (their user ID),
concatenate the three values together, hash them, then with the second hash
function either hash the hash and store it, or hash the values again
separately and store both hashes._

... based on this, you either (a) have no clue what you're doing, or (b)
utterly fail at explaining what you're doing, given that I haven't a clue what
you're trying to do.

Let's start at the beginning: What problem are you trying to solve? Don't try
to explain a potential solution -- explain the problem, phrased something like
"I have X, and I want to be able to do Y, but want to make sure that an
attacker who is able to do Z doesn't become able to do W".

~~~
cryptonewbie
Thanks for the reply.

I am building a web application, and I need to be able to store the passwords
of its users securely on disk. I know hashing them with a salt and nonce is
better than nothing, and that you should avoid older, broken hash functions
like MD5 or SHA-1 and opt for something like SHA-256, but beyond that I am
kind of at a loss.

~~~
cperciva
_I am building a web application, and I need to be able to store the passwords
of its users securely on disk._

Define "securely". What sort of attacks are you concerned with? Someone trying
passwords via your web application? Someone breaking into your server and
reading the hashed passwords from disk? Someone installing a rootkit and
grabbing users' passwords as they log in?

~~~
cryptonewbie
I would like the protocol to be secure to the point that an attacker
possessing a stolen hard drive with the database containing users' passwords
on it, would be unable to either a) figure out what the plaintext password of
any user is, or b) generate a new password such that it, when put through the
protocol, results in the same hashed/encrypted password of a user.

If they can install a root kit, perform a cold boot attack or something
similar (access the RAM), I'm willing to concede to them.

~~~
cperciva
Now we're getting somewhere. :-)

When a user's password is set, generate a random salt, compute K =
scrypt(salt, password), and store (user, salt, K) in your database. To verify
a password, look up the user's salt value, compute K' = scrypt(salt,
password'), and compare K' to K.

You don't need this much strength, but as a matter of course I would recommend
using a 256-bit salt and a 256-bit output from scrypt -- the reasoning being
that using 256 bits isn't going to be a performance-limiting factor, and that
if you try to figure out exactly how many bits you need, there's a risk that
you'll make a mistake.

If you can't use scrypt, I'd recommend PBKDF2-SHA256; if that's also
unavailable, use bcrypt.

~~~
cryptonewbie
Thanks!

------
ErrantX
ok, here's how I do it (this is in turn stolen from a framework I use).

generate a random salt

concatenate the salt and password and hash them up

then I take a known array of integers the same length as my salt and slice the
salt into the password hash using the integers as offsets and store the
result.

For password comparison that salt can then be extracted using the same offset
array.

I've found this to be a great trade off: if the array of integers is kept safe
it is next to impossible to attack the stored "key". If the offset is known
someone else can extract the salt: but because each person has an individual
salt it still invalidates any table based attacks on the hash.

There might be theoretically more secure schemes: but I think this one has the
best tradeoff of simplicity and security!

(the original method comes from the KohanaPHP framework's example auth module
by Woody Gilk)

------
sweis
If you're concerned about physical theft of the hard drive, why not encrypt
everything that is written to disk?

