News for hackers. Stuff that matters.
Re:How To Safely Store A Password by timtadh on Tuesday December 14, 2010 @02:11PM (#2005308)
B-crypt and S-crypt are great libraries to use to solve this problem. However, the poor man's approach is as follows with HASH being your favorite hash function

    h = HASH.new()
    HASH.update(password)
    HASH.update(salt)
    for x in xrange(X):
        HASH.update(HASH.digest())
    return HASH.digest()
this approach "strengths" the hash by forcing you to calculate it over and over again. You should set X to be the number of rounds you want to conduct. Ie. how slow you want you server to respond to an individual request. It is always a trade-off between server slowness for individual requests and "security" of the hash function. The goal is to make dictionary attacks take longer than is feasible for you attackers to conduct.

[Note: you should absolutely have a different salt for each password with this approach.]

Re:How To Safely Store A Password by tptacek on Tuesday December 14, 2010 @02:13PM (#2005316)
For what it's worth: this is essentially PBKDF2.
Re:How To Safely Store A Password by cperciva on Tuesday December 14, 2010 @03:03PM (#2005523)
Actually, it's essentially PBKDF1, but that's close enough for non-cryptographers.
Re:How To Safely Store A Password by tptacek on Tuesday December 14, 2010 @04:29PM (#2005797)
Shit, you're right. (PBKDF2 generates arbitrary-length output, which is what you want from a key derivation function, but maybe not something you care about for a password hash).

Here's a version that's much easier to read than the spec:

https://github.com/emerose/pbkdf2-ruby/blob/master/lib/pbkdf...

I should stop saying PBKDF2 and just go back to saying PBKDF.

Re:How To Safely Store A Password by cperciva on Tuesday December 14, 2010 @05:09PM (#2005929)
PBKDF2 also protects against entropy loss from repeated iteration, although that doesn't really matter unless you're using an unreasonably short hash.
Re:How To Safely Store A Password by brown9-2 on Tuesday December 14, 2010 @02:46PM (#2005462)
Why would you use this "poor man's approach" over bcrypt or scrypt? My understanding is that these two work on a very similar concept (work factor) and are free to use.
Re:How To Safely Store A Password by ams6110 on Tuesday December 14, 2010 @10:52PM (#2006971)
Some projects require FIPS 140-2 compliance. I've not been able to find that blowfish or bcrypt are certified. See http://csrc.nist.gov/publications/fips/fips140-2/fips1402ann...
Re:How To Safely Store A Password by burgerbrain on Tuesday December 14, 2010 @11:26PM (#2007057)
If a randomly clobbered together and unvetted system is compliant, but bcrypt isn't, that just goes to show how little FIPS140-2 compliance actually means. (as if everybody didn't already know it's worthless)
Re:How To Safely Store A Password by ams6110 on Tuesday December 14, 2010 @11:40PM (#2007078)
Nonetheless, some projects mandate use of FIPS 140-2 hashing algorithms, and afaik bcrypt is not one. So if you find yourself on such a project, bcrypt is not an option on the table.

I'd be happy to find out I'm wrong.

Re:How To Safely Store A Password by csytan on Tuesday December 14, 2010 @05:25PM (#2005985)
I can think of one reason: Lack of the available libraries on a particular platform.
Re:How To Safely Store A Password by timtadh on Tuesday December 14, 2010 @06:22PM (#2006182)
This is why I mentioned it. It provides improved time guarantees for your users with out needing another library.
Re:How To Safely Store A Password by paperclip on Tuesday December 14, 2010 @06:25PM (#2006192)
bcrypt is open source and ported to a range of operating systems. I cannot imagine getting it up and running on any system would be too difficult. It would probably be wiser to to spend the time to get bcrypt (or another standard scheme) working rather than coming up with some custom scheme which probably hasn't had the same level of thought put into it.
Re:How To Safely Store A Password by jrockway on Tuesday December 14, 2010 @05:45PM (#2006064)
Because building your own square-shaped wheel is more fun than talking a walk over to your friendly neighborhood wheel store and buying a round one?
Re:How To Safely Store A Password by burgerbrain on Tuesday December 14, 2010 @07:03PM (#2006344)
Because we all know rolling your own in the crypto world instead of deferring to the experts never leads to catastrophe!
Re:How To Safely Store A Password by brown9-2 on Tuesday December 14, 2010 @11:19PM (#2007037)
You assume those are the only two choices, I was considering that in some environments these might be the only two choices when I asked the question.
Re:How To Safely Store A Password by IgorPartola on Tuesday December 14, 2010 @05:34PM (#2006016)
Why not also add

  HASH.update(salt)
On each iteration as well? Then again, if things were this simple, someone would have already said "just do this", it would have been peer-reviewed and would have become widely used. Anyone know why this hasn't caught on yet in web frameworks like Django/Rails?
Re:How To Safely Store A Password by Xk on Tuesday December 14, 2010 @05:47PM (#2006069)
If you're talking about why you don't do hash.update(salt) on every round, well it turns out that H(salt || H(H(H(H(H(H(password))))))) is just as strong as H(salt || H(salt || H(salt || H(salt || H(salt || H(salt || H(salt || password))))))). So you don't add any security by doing that.

When working with cryptography, "why not also add" is really dangerous, because some times you get less secure systems after doing so. And other times you get no benefits from doing so.

Re:How To Safely Store A Password by gcr on Tuesday December 14, 2010 @06:41PM (#2006253)
Could you explain a bit more about this?
Re:How To Safely Store A Password by Xk on Tuesday December 14, 2010 @06:55PM (#2006307)
(Aside: I'm sure that tptacek could give a significantly better answer here than I can, but I'll give it a shot. (And then whenever he answers trust him more than me.))

Assume you have a perfect cryptographic hash function H(X). No matter how many of N bits of X you change (0 < N <= len(X)), on average 50% of the bits of H(X) will change. So, let's consider the case of just H(salt || H(salt || password)) versus H(salt || H(password)).

Let A = H(salt||password), and let B = H(password). A and B are now, for all practical purposes, two different random integers. Each of which has the same entropy. This is because adding the salt should make no impact on the quality of these random numbers. It should now be fairly easy to see that there is no difference between H(salt||A) and H(salt||B), other than the fact that they produce different outputs.

This is all based on the assumption that the hash function is a perfect one -- however this assumption is reasonable for strong hash functions.

Re:How To Safely Store A Password by Raphael on Tuesday December 14, 2010 @08:11PM (#2006566)
What value of X would be good for a web app? 10? 100? 1000?
Re:How To Safely Store A Password by tptacek on Tuesday December 14, 2010 @08:15PM (#2006574)
1000 is a minimal value.
Re:How To Safely Store A Password by timtadh on Tuesday December 14, 2010 @08:19PM (#2006583)
As I said, it depends on how slow you want your server to respond to a given request. For instance, you could set X so high that it takes a minimum of 1 second to respond to a request. That is probably not necessary. The real answer is you need to take the estimated minimum amount of time to calculate one of hash using the function you have chosen. Then compute using that number as the basis the minimum number of rounds to assure reasonable security for a single password. Reasonable security could be it would take 1 year to a do a full dictionary attack alphanumeric only or perhaps 1 month or 1 week. The value you choose for the time it takes to brute force one password is the level of protection you are providing your users.

EDIT: also what Thomas said. It is in the standard that 1000 should be the minimum value. I would use higher based on the level of protection you want to give your users. Note that different hash functions have different costs so this will also impact the choice of X.