views:

67

answers:

2

I am contributing to a relatively mature open-source PHP project. Recently, I discovered that it stores passwords as plain MD5 hashes, which is quite bothersome to me. I figured that if I was going to fix it, I might as well Do It Right(tm), so I wanted to use bcrypt.

First, what I have found for other languages: bcrypt-ruby appears to use either the original C code from OpenBSD or jBCrypt's java code. py-bcrypt is a thin wrapper around the BSD code. BCrypt.net is a direct port of jBCrypt.

Now, PHP itself supports bcrypt (albeit, misleadingly called simply 'blowfish') in the crypt function. However, versions prior to 5.3 require support on the system itself, generally provided by crypt_blowfish. phpass is the same, and recommends installing either PHP 5.3 or Suhosin.

Since many users of the application use standard shared hosting, I don't want to require any special configuration of the server. I was hoping to just steal the code from PHP's 5.3 release, but it is in C, and (from the small bit of reading I've just done) I cannot require the use of a C-extension for the project's users.

I thought of just creating a pure-PHP port of bcrypt, but looking at the source of jBCrypt, I am not sure that I should, given that I'm not incredibly familiar with either PHP or blowfish, and a mistake here could be simultaneously dangerous and difficult to detect in the first place.

So, I present to you two (multipart) questions:

  1. Is my lack of PHP knowledge getting the best of me? Can I really use one of the already-created implementations?
  2. Should I instead just create a simple loooping function that calls sha1() or md5() repeatedly for some configurable number of times?
+7  A: 

Recently, I discovered that it stores passwords as plain MD5 hashes, which is quite bothersome to me. I figured that if I was going to fix it, I might as well Do It Right(tm), so I wanted to use bcrypt.

You should definitely NOT encrypt passwords. Passwords should be hashed and salted.

Encrypted passwords can be recovered, hashed passwords can't (at least that's the theory). Sure, there are ways to use symmetric encryption algorithms as hash functions, but why do that instead of using real hashing functions like the SHA family?

If you are concerned about the security of MD5 (you should be), you can use the SHA family of hash functions. Also remember to salt the passwords to foil rainbow table attacks. Salting is almost as important as hashing.

Read: Just Hashing is Far from Enough

NullUserException
+1 for not encrypting passwords. Hashes should always be used.
Rook
Although bcrypt is actually a hash function built out of a block cipher...
Rook
Null, do you have any resources to throw at the issue below?
Steven Sudit
@NullUserException also note that i voted you up, even though you where wrong about bcrypt. :)
Rook
A: 

The "Right Way" is to use sha256 and here is a php implementation. Salts should be a large cryptographic nonce approximatively the size of the hash function you are using. It is common to store the salt in a column in the database, and it is common for attackers to obtain this value and break the salted hash with something like John The Ripper.

The use of encryption for passwords is a clear violation of CWE-257. Unless of course you are using a block cipher as a message digest function which bcrypt does. However, bcyrpt is very old, no one should use this anymore. Blowfish should never be used when there is more modern ciphers to choose from like two-fish, AES and Serpent. Further more SHA256 is more efficient than bcrypt.

The whole point of a hash function is that they are FAST to calculate in one direction and slow to reverse, they should never be looped to increase complexity. This doesn't make you safe this just slows down your program. bcrypt is an iterative calculation because the output of a blockcipher is used as a feedback in order to create a message digest. NIST will never approve of using a slow message digest function. You have been misinformed.

Rook
What do you think of PBKDF2?
Steven Sudit
@Steven Sudit not suitable for web applications because it is extremely heavy. Its not going to stop anyone from breaking the hash, especially if you have a dictionary password.
Rook
@Steven Sudit also this algo is used for applications where the attacker has the hash, such as winzip and encrypted file systems. These security systems are fundamentally flawed. An attacker should never be given the hash.
Rook
I'm not sure I understand your objection. Yes, it's "heavy", but configurably so, and this is intentional. As for breaking it, if it takes 1000 times longer to generate a rainbow table entry than with plain SHA-1, then that can definitely be a barrier. It also includes a salt, so you would need to make a custom rainbow table, even with a dictionary of likely passwords.
Steven Sudit
I'm not suggesting that the attacker be given the hash. This algorithm has multiple purposes. One is to take a single, relatively weak password and generate any number of relatively strong ones (hence the name). Another -- which is the one we're talking about -- is to take a password with salt and generate a good hash.
Steven Sudit
@Steven Sudit Keep in mind the OP is talking about an open source web application. This app could be used by many thousands of people at the same time. No one can use PBKDF2, its not a matter of choice. I personally believe it is very unnecessary. I have generated rainbow tables and I can tell you if you are using a salt that is 256byte long then we don't have a word the size of table you'd have to generate to crack a password that is a single alpha character, that is a great trade off. PBKDF2 is not a good trade off.
Rook
@Steven Sudit the use of PBKDF2 also makes you more vulnerable to DDoS attacks. It is better to use a good hash function like SHA256 and then test your application for attacks like SQL Injection which are commonly used to obtain password hashes and salts. This produces a efficient and very secure web application.
Rook
One objection at a time. First, here's a Ruby implementation: http://github.com/emerose/pbkdf2-ruby
Steven Sudit
I'm not sure I understand what you're saying about rainbow tables: you might have omitted one or two words somewhere. If you're generating a table for a cheap function (single-iteration SHA256), it'll take you a thousand times longer than with PBKDF2 (or more, if we increase the iteration count).
Steven Sudit
As for DDoS, you're vulnerable even with CRC-32. The solution is throttling, not dumbing down the hash.
Steven Sudit
@Steven Sudit When you are generating a rainbow table you have to give it a password size range, like 6-10 chars and mixed-alpha-numeric (http://98.15.203.119/BruteForce%20Cracking%20Tools/Parameter%20Optimization%20of%20Time-Memory%20Trade-Off%20Cryptanalysis%20in%20RainbowCrack.htm), they have matlab scripts to calculate the size. A table like this will take a few days to generate and it will be a few gigabytes in size. A salt forces you to generate a table that is the strlen(password)+strlen(salt), and no attacker is going to spend this kind of time to break passwords with a huge salt.
Rook
@Steven Sudit In terms of CRC vs PBKDF2 your comparing a small breeze to a massive hurricane. Magnitude is everything. Also it apples and origins, its trivial to generate a collision for crc32 because it is not a cryptographically secure hash function.
Rook
If you're saying that any salt of decent size (about as wide as the hash output) is going to stop rainbow tables dead, you're probably right. However, if you just want to figure out the password behind a hash that you have the salt to, then brute force will work fine with SHA256. On the other hand, PBKDF2 makes that untenable, as that rainbow table would take years, not days, to generate.
Steven Sudit
@Steven Sudit People don't use rainbow tables to attack heavily salted hashes, small salts are different story. An real world attacker is going to use something like John The Ripper or Cain and Able to break a salted password. Once the attacker has the salt its trivial to hit with a dictionary, and most passwords will break even if they are protected by PBKDF2.
Rook
@Steven Sudit people break winzip all the time..
Rook
A successful DDoS attack can be launched against a statically served URL. It's even easier against a URL that does SQL lookups. If you don't throttle, you're already vulnerable. You have nothing to lose by accepting an intentionally expensive hash, but there is something to gain from this.
Steven Sudit
Ok, what technique do they use to break WinZip?
Steven Sudit
@Steven Sudit http://www.openwall.com/passwords/ace-arj-rar-zip-archives
Rook
@Steven Sudit again magnitude is everything. If it too heavy for the attacker, then its too heavy for a server farm hosting the site.
Rook
Uhm, I'm somewhat familiar with both of these tools, but I don't think either handles PBKDF2. Am I mistaken?
Steven Sudit
@Steven Sudit John the Ripper doesn't have a module for sha256, but its trivial to add one. Hackers are programmers too ;)
Rook
Steven Sudit
@Steven Sudit openwall is where jtr is hosted. The script kiddies aren't the ones you should concern your self with when building a security system. You need to worry about people like me who write exploit code and post on bugtraq.
Rook
I'm realizing that (quite intentionally) this is a terrible environment for a conversation. Having said that, your advice about avoiding slow, iterated password digests goes against what I have seen elsewhere. Would you be able to point to some reasonably reliable source that supports your conclusion? I think that doing a bit of research would be more productive that debating this here. :-)
Steven Sudit
Steven Sudit
@Steven Sudit I'm sorry but I don't know of any good papers on either side of this argument. The proponents of iterative hashing for web applications is deeply concerning to me as none of these people are distinguished cryptographers. As someone who has broken password hashes I believe the approach is severely flawed. (On a side note the use of a salted sha1 would be approved by NIST and not a violation of any CWE http://cwe.mitre.org/)
Rook
Yeah, Mitre audits me, so I'm familiar with their standards. If you want a good example of the multiple iterations POV, try http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html. If there's no good response out there, perhaps you're the person to write one. :-)
Steven Sudit