Cheap GPUs rendering strong passwords useless?
zdnet.com
zdnet.com
This is a great example of a bona fide awful trade press article: some guy with a column-inch quota sees a piece by another trade press hack who is in turn digesting a blog post by someone who is "allergic to command line utilities" writing up someone else's GPU password cracking tool. And so, strong passwords are useless!
Except that this has nothing at all to do with why passwords are bad. The problem GPU crackers exploit was solved over a decade ago with adaptive hashing. GPU crackers cannot crack scrypted passwords of any real complexity in tenable amounts of time.
Once again: http://codahale.com/how-to-safely-store-a-password/
Edit: Since I can't reply to poster. I don't see bcrypt using a unique salt for each password. It's the equivalent of exchanging a SHA256 + Same Salt for Bcyrpt + Built-in-Salt.
Does bcrypt use a unique salt per account?
You can find the answers to your bcrypt questions at the Usenix paper which is the first link in the article you're advising people not to read.
[8:48pm:~] RIDGELAND:tqbf [1:45]% irb -rrubygems -rbcrypt
>> BCrypt::Password.create("test password")
=> "$2a$10$KyxzQ6ZlAAYdLWwpgCbyjuqo53.LzPbsaSK2BiTnzpYEpRVZOHAAy"
>> BCrypt::Password.create("test password")
=> "$2a$10$d0uUieyk0NWsU7E9CmQNwOsveyznwKwplphsF73yILdEyStmoUGgG"
Notice how they aren't the same hash? And, how I didn't have to go mine pink salts from the Himalayas?By spreading the notion that there is something wrong with Coda's article when you really aren't familiar with bcrypt, you're doing people a disservice. They are going to go use SHA1 with a big random salt instead, because they've heard of SHA1 before and it therefore sounds more secure. And they will thus be terribly vulnerable to brute-force attacks.
I'm not saying you're wrong. I'm saying you didn't demonstrate proof, so you shouldn't act like you did.
I'm extremely interested why bcrypt is much more secure than SHA1 + extremely long hash, so perhaps you could shed some photons on that?
Also, in order for bcrypt to generate a unique salt on two different computers, it needs a unique source of randomness. Obviously seeding by "current time" is insufficient, as this would generate the same salt for two different computers at the same time. So what does it use? Mac address of network card + current time?
How frustrating to have to argue about a system with someone who clearly hasn't done any reading on it at all. It's a Usenix paper. It's not a EUROCRYPT paper full of math. It was written by systems programmers, then from the OpenBSD project. You think the OpenBSD programmers devised a password scheme with a "preset list of nonces"?
"MAC address of the network card plus the current time"? To get a random number?
you're trolling, right?
If not, begin your journey to enlightenment at http://www.cs.berkeley.edu/~daw/papers/ddj-netscape.html (15 years old now!), http://www.schneier.com/paper-prngs.pdf and the kernel source for your favourite OS' /dev/random (the OpenBSD one is pretty well commented)
The algorithm requires (cost, salt, password) as input, and the output hash includes the cost and salt. When generating a hash for a new password you should of course be choosing this salt randomly, and when checking a password be using the stored cost and salt.
In particular see the Implementation section:
An important requirement of any bcrypt implementation is that it exploit the full 128-bit salt space. OpenBSD generates the 128-bit bcrypt salt from an arcfour key stream, seeded with random data the kernel collects from device timings.
Seriously though, this is a design decision that cannot be easily solved with any non-reversible encryption. If you were able to increase the cost factor, the you'd open the algorithm to attacks that reverse that process.
work * costfactor
finish
The finish step is irreversible, so you can't unwind it and add more work later. In practice though, even low cost factors for bcrypt are tons more work than MD5 or SHA. It's not a big deal. bcrypt( bcrypt( "foo", c1 ), c2 )So, initially, you are storing b(pass,C1). Running C2 on top of C1 would mean replacing that with b(b(pass,C1),C2).
Later, when you want even more work, another layer could be added: b(b(b(pass,C1),C2),C3) and so on.
Right now, I have b(password, c1) = hash_a stored in my database. To increase the cost to c1+c2, I just replace that with b(hash_a, c2) = hash_b in my database. To verify a user's login, I just compute b(b(password, c1), c2) and compare it to the hash_b I have stored.
Am I missing anything?
Basically, the assumption that bcrypt is just a function that returns a hash oversimplifies the detail of how salt is stored in practice.
I agree: this is not a big deal in practice. bcrypt with a cost factor of 10 is so much slower than SHA1 that this is just not going to be an issue.
The fact is that any significantly high cost factor is much better than md5, sha1 or any other normal hashing function, and should prevent password cracking for 5-10 years. This is a reasonable period of time.
The fundamental issue is that of salting combined with not disclosing your password database. If you're using Windows you should enable the options for SSHA and disable the NTLM / LM hashes. Instead of using a password use a passphrase. I use 3 levels of password and at the top level you're looking at ~22 characters which contains characters outside the normal ASCII range so an attack is looking at ~65536 combinations instead of ~256. I doubt many attackers include the snowman character. :) (and no that char isnt in my password)
Running the math quickly yields a time to crack in excess of the lifetime of the universe, it would probably be easier to generate a hash collision than crack the password.
The aim of password storage security is to prevent pre-computed hashing reasonably enough. No amount of password hashing even if it takes 1000 years to hash a password if your users use '12345678' as a password.
Salting protects against pre-computed hashes (rainbow tables [0]). Otherwise I can pre-compute many bcrypt hashes and then quickly look up the password.
[0] https://secure.wikimedia.org/wikipedia/en/wiki/Rainbow_table...
All secure password storage schemes are randomized. If you insist on using the word "salt", then just know that bcrypt, scrypt, and the PBKDFs build the salt in. You cannot "pre-compute many bcrypt hashes and quickly look up passwords". So: if you're using a scheme that requires you to think about salts, you are virtually certain to be using an insecure storage scheme.
And, dictionary and brute force attacks are the entire problem bcrypt is designed to address. Go back to that article that you didn't really read, follow the first Usenix link, and read the Usenix paper it cites.
Some functions[0][1] seem to optionally allow the use of salt, are you saying that users should just use passwords as input with bcrypt hashing?
In the article, it does not suggest only bcrypt as well [2].
[0] http://www.mindrot.org/projects/py-bcrypt/
[2] http://www.usenix.org/events/usenix99/provos/provos_html/nod...
The bcrypt libraries that require users to explicitly provide a salt are themselves doing their users a (slight) disservice, by making it seem as if there was a reasonable option for salt generation other than simply using a CSPRNG.
... and this is another reason why people should use one of the bcrypt() implementations for their language* - the API makes doing the wrong thing difficult or impossible.
* disclosure: I ported/wrote a couple of them
Quick quiz: how does HN store passwords? How about apple.com? Facebook? Twitter? Gawker? Sony Pictures? Perlmonks?
A suitably paranoid person would assume any password you've given to somebody else's website is compromised.
Do not reuse passwords ever. Don't even think "I'm just trying this new web service out, I'll use the same password I always use when trying new things out", 'cause you'll end up forgetting to upgrade that password when something gradually changes from "some new and maybe interesting website" to "somewhere that is an important part of my online reputation" or "somewhere I've given authority to charge my credit card".
(and, even more importantly, don't ever fall into that trap when developing server side code "Oh, I'll just do a quick login method for testing that just stores cleartext passwords, I'll fix that bit up before we go live..." Because one day that code _might_ end up live...)
Unsalted SHA1.
(def shash (str)
(let fname (+ "/tmp/shash" (rand-string 10))
(w/outfile f fname (disp str f))
(let res (tostring (system (+ "openssl dgst -sha1 <" fname)))
(do1 (cut res 0 (- (len res) 1))
(rmfile fname)))))
... (and user pw (aand (shash pw) (is it (hpasswords* user))))Instead, all the top 25 passwords found in the recent Sony exposures from here: http://www.troyhunt.com/2011/06/brief-sony-password-analysis... are found in that well known rainbow table, Google...
iains-imac: bigiain$ echo -n 'bailey' | openssl sha1 b1f45ed147d6803ac1a2a91bdea1fab603f910a5
http://www.google.com/search?q=b1f45ed147d6803ac1a2a91bdea1f...
If HN ever gets 0wn3d, anybody with a (password) dictionary word or 8-9 char or less password will almost certainly be exposed. (even if the database doesn't get broken into, anybody who gets enough shell on the webserver to read /tmp/shash will be able to see cleartext passwords passing through...)
The solution is to use tools like KeePass or 1Password to allow maximum length passwords (randomly generated also) wherever possible.
Pretty horrible. I wonder what level of idiot designs these systems.
In my example, they could put a sensible account system on the front end, and do whatever they need to in the back end to link it to my phone number and a random 8 digit number, if that's what they need.
Same with banks. They can set up a real user name and password from you, store it in a modern system, and link it to the older system behind the scenes. Perhaps there's some arcane legislation that prevents this, but it seems unlikely.
Can anyone compare this to the actual MSFT recommended Kerberos security protocol?
Also, how does one go about getting a list of NTLM passwords to work against? You steal the domain controller or somehow get access to it?
http://en.wikipedia.org/wiki/NTLM MSFT does not recommend using NTML which is very old.
http://msdn.microsoft.com/en-us/library/cc236715(v=PROT.10)....
Implementers should be aware that NTLM does not support any recent cryptographic methods, such as AES or SHA-256. It uses cyclic redundancy check (CRC) or message digest algorithms ([RFC1321]) for integrity, and it uses RC4 for encryption. Deriving a key from a password is as specified in [RFC1320] and [FIPS46-2]. Therefore, applications are generally advised not to use NTLM.<68>
If you can dump the db then (most likely) you also have the credit cards, other information that is useful to you?
This assumes a hacker has a financial motivation.
There are many conceivable attacks that would result in a read-only dump of password hashes. An administrator's account would be useful in such an administration, turning your read-only access to read-write access.
The technique in the article is relevant when one has the hashes and wants the plaintext (and according to some here, still easy to mitigate then) - if you're guessing a web login, different game.
I'd be curious about the timeliness of GPU cracking a 8 character, alphanumerical mixed case password hashed with SHA1?
Cryptographers have a mechanism for securely turning human-readable text into secret material: key derivation functions. All the modern KDFs are adaptive, meaning that they come with a "pain" dial that you can turn to force attackers to spend more time executing crypto code paths and less time comparing results.
You can build decent KDFs out of functions like SHA1, but if hardware GPU cracking is the future, you're best off with something like Colin Percival's "scrypt", which was explicitly designed to be memory-hard (requiring lots of state to compute) and hard to parallelize:
At any rate, you can download ighashgpu and try it for yourself.
So at peak rates I think that would come out to around 26 hours.
Combinations/SHA1HashesPerSecond/SecondsPerHour
(26 * 2 + 10) ^ 8 / (2300 * 1000000) / 3600 = 26