How To Safely Store A Password
codahale.com
codahale.com
The other day, I saw the following post about password hashing in my RSS feed: http://isc.sans.org/diary.html?storyid=11110
- No mention of bcrypt (though the posts mentions key stretching using SHA1)
- "When selecting an algorithm to hash passwords, it is important to select carefully as it is difficult to change the algorithm later. You will have to ask users to change their password if you do as you no longer know what password they picked." --> seriously? you can update the password the next time they log in...
- "You could also add a secret, in addition to the salt. If the secret is not stored in the database, it would not be easily reachable via a SQL injection exploit (yes, you can use them to read files, but it requires sufficient privileges)." --> security through obscurity, nice
- "For the paranoid, you may want to do the hashing on the client side (javascript) . This way, the server never receives the plain text password. We do this here for the ISC website on our login form [2]." --> oh noes...
Note that the blog has ~15k subscribers according to Google Reader...
---------
I also launched a debate on StackOverflow the other day. A self-proclaimed "security expert" (he later edited his post to remove this part) was advising against using bcrypt, arguing that it would facilitate DOS attacks against the login page... He prefers security through obscurity, using a secret salt:
http://security.stackexchange.com/questions/4781/do-any-secu...
I thought it was a bad idea to leave this answer unchallenged, so I tried arguing with him. I was met with arguments of authority such as "Wow you are out of your element and could not be more misguided on this topic" or "you disagree because you don't understand. Show me an exploit you have written, then I'll pay attention to you.". Happily, some (more experienced) people got in on the debate. I hope this will help developers make an informed choice, if they stumble upon his answer...
(edit: list formatting)
http://groups.google.com/group/linux.debian.user/browse_thre...
http://www.akkadia.org/drepper/sha-crypt.html
which the version of crypt(3) in glibc. It is almost the same as bcrypt. One difference is that it uses SHA256 or SHA512 instead of Blowfish. But that implementation has the same ability to expand the work factor like bcrypt.
So I'd say that the algorithm they're using is slow and is designed to be slow
> What about Debian's reason for not using bcrypt, claiming the time it takes to hash is not a weak point in security of /etc/shadow?
That's a good question, but I'm not sure the discussion you linked to really explains why Debian does not use bcrypt. The first post is, ironically, the most interesting one: it links to Coda Hale's great article, and to a StackExchange question where we learn that bcrypt has been OpenBSD's default password scheme since OpenBSD 2.1 (http://www.openbsd.org/papers/bcrypt-paper.pdf). OpenBSD being well-known for its code quality and security focus, this would indicate that bcrypt is actually quite adapted for OS password hashing.
Some critics:
First, if you don't have the salt, but you do have the hash, then a rainbow table attack is completely pointless. Reason being is rainbow tables store hashes with a 1:1 ration to text. How the table is traversed is another story, but the fact remains that one hash will lead you to one piece of text. Now add a salt. If the salt is unknown, the length of the salt is 8 characters, and the characters used in the salt are [A-Za-z0-9./], or 64 characters, then there are effectively 64^8 possible hashes for one password. That's 281474976710656 hashes. Even moving at 700,000,000 passwords per second, you have to generate that many hashes per password. Point is, you have one massive keyspace to search through. Good luck.
Here, Aaron says that salts defeat rainbow tables because they are secret, thus increasing the keyspace. While not knowing the salt does complicate password cracking, this is not the reason we use salts. Rainbow tables let crackers trade time for space: they pre-compute password hashes once, and then use this table to avoid brute-forcing each password separately. A salt defeats this because it forces the cracker to either generate a very big rainbow table, which is impractical, or to generate a different rainbow table for each salt, which is the same as brute-forcing... This has nothing to do with the salt being secret. Your only goal here is to have a random salt (a nonce, ideally).
Lastly, the SHA1 and SHA2 algorithms were designed with security in mind. Sure, they're fast, but that's the point. If you're concerned about knocking a login prompt, you shouldn't be considering the speed of the algorithm. Instead, you should be spending your time learning PAM. If you're concerned about someone brute forcing an unshadow file, bcrypt isn't going to help you if the password is low in entropy (he gives an example of a 6-character password- seriously???). If your password is high in entropy, as it should be, then even if SHA1 could churn through 400GBps, it's not going to find it. Case in point, consider http://distributed.net hacking the 72-bit RSA key. 72-bits of entropy, and it would take them 1,100 years at their current rate to exhaust the keyspace entirely. That's only an 11-character password with [A-Za-z0-9] and [:punct:] as the possible characters. 1,100 years for an 11-character password.
Here, the argument is that there is no need to use bcrypt if the user chooses a password with a high entropy. That may be true, but then, what's the problem with making brute force attacks even slower by using bcrypt (or another slow hash function)? Low-entropy passwords would be harder to guess. High-entropy passwords would be impossible to guess.
The rest of the discussion focuses on the use of salts, and on how Debian stores these salts in the /etc/shadow file. At no point do they really talk about key stretching / bcrypt.
------------------------------------------------
Now, I decided to look at what Debian currently uses for password hashing. In the latest login.defs file ( http://anonscm.debian.org/viewvc/pkg-shadow/debian/trunk/deb... ), you can see:
# If set to MD5 , MD5-based algorithm will be used for encrypting password
# If set to SHA256, SHA256-based algorithm will be used for encrypting password
# If set to SHA512, SHA512-based algorithm will be used for encrypting password
# If set to DES, DES-based algorithm will be used for encrypting password (default)
# Overrides the MD5_CRYPT_ENAB option
#
# Note: It is recommended to use a value consistent with
# the PAM modules configuration.
#
#ENCRYPT_METHOD DES
#
# Only used if ENCRYPT_METHOD is set to SHA256 or SHA512.
#
# Define the number of SHA rounds.
# With a lot of rounds, it is more difficult to brute forcing the password.
# But note also that it more CPU resources will be needed to authenticate
# users.
#
# If not specified, the libc will choose the default number of rounds (5000).
# The values must be inside the 1000-999999999 range.
# If only one of the MIN or MAX values is set, then this value will be used.
# If MIN > MAX, the highest value will be used.
#
# SHA_CRYPT_MIN_ROUNDS 5000
# SHA_CRYPT_MAX_ROUNDS 5000
In my Ubuntu 11.04 install, ENCRYPT_METHOD was set to SHA512 (in /etc/login.defs). SHA_CRYPT_* is not specified, so the default number of rounds is used (5000). I think this means that, by default, Ubuntu hashes password by salting them and encrypting them 5000 times with SHA512. So, Debian uses salted stretched SHA512, which does slow down brute forcing a little... But is still not ideal when compared to bcrypt.I see no real reason to avoid bcrypt when hashing OS passwords. Maybe they avoid it for backward compatibility? Maybe because it is not standard enough yet? Maybe they want to comply with FIPS 140-2?
Other great discussions on bcrypt / password hashing:
http://news.ycombinator.com/item?id=995634
http://news.ycombinator.com/item?id=1592007
My impression is that SHA512 with 5000 rounds is competitive with bcrypt (per Schneier in February, at least). But ... this is not the default on Debian, DES is, which I understand is not remotely competitive with bcrypt.
I checked my server, and it uses the default DES... time to harden the passwords.
Refs
1. SHA512 vs. Blowfish and Bcrypt - http://stackoverflow.com/questions/1561174/sha512-vs-blowfis...
2. Schneier on SHA-512 variants http://www.schneier.com/blog/archives/2011/02/nist_defines_n...
- when a webapp loses its user table, the devs will be responsible for compromising thousands of password (which user often re-use elsewhere). This is what happened with the Gawker hack and the recent lulzsec database dumps.
- when somebody accesses your /etc/shadow file, he likely already has root access to your machine, so you are pretty much owned anyway. Protecting your password might help a little, but it's less useful than in the above case.
tptacek talked a little about this in one of the posts I linked above: http://news.ycombinator.com/item?id=1091445
------------------------
Now, to address your point: stretched SHA512 (SHA512 iterated 5000 times) is indeed a lot better than calling SHA512 once. But bcrypt still has some advantages over it by design, which makes it even better for password hashing. Some links:
http://news.ycombinator.com/item?id=1091465
http://news.ycombinator.com/item?id=995685
http://chargen.matasano.com/chargen/2007/9/7/enough-with-the...
------------------------
Regarding your second link (Schneier on SHA-512 variants), I don't see anything about bcrypt or password hashing there. He talks about the advances of hash functions, but those are fast hash functions. Fast hash functions are very useful in cryptography, but they are the opposite of what you want for a password hashing scheme.
the only argument i've heard is that sha-2 can be implemented in specialized hardware (well-funded attacker) that is much much faster than CPU/GPU, whereas this is not as easy for bcrypt?
however, with multi-iteration hashing, you can strengthen the hash further w/o the user having to log in again.
http://news.ycombinator.com/item?id=1091465
> the only argument i've heard is that sha-2 can be implemented in specialized hardware (well-funded attacker) that is much much faster than CPU/GPU, whereas this is not as easy for bcrypt?
Yep. I think that's one of the main reasons. As tptacek said in the above link:
"There's a difference: bcrypt (and moreso scrypt) were designed to be hard to speed up, while SHA1 was designed at least in part to be easy to speed up."
In my opinion, the main advantage of bcrypt is the simplicity. It handles everything for you: salting, "slow" hashing, password checking. You simply have to specify a work factor and you are good to go. No need to implement any crypto yourself.
> however, with multi-iteration hashing, you can strengthen the hash further w/o the user having to log in again.
That's a very good point, I hadn't thought about that. I wonder if we can do this with bcrypt too.
IMO, as long as you use either bcrypt, scrypt, PBKDF2, or password stretching, you are good to go...
Hashing ≠ Encryption.
Unlike encryption, where an encrypted message is intended to be decrypted by a trusted party, a hashed password is never intended to be 'unhashed'. Rather, the hash of the password supplied by the user is compared against the hash value stored in the database. Given a sufficiently strong password P, it should be computationally infeasible for anyone to compute the value of P from hash(P).
After all, an attacker does not need to recover the password from the hash, all he has to do is capture the hash and replay it.
Also, tptacek made a few interesting comments about client-side cryptography:
http://news.ycombinator.com/item?id=1755713
http://news.ycombinator.com/item?id=1756394
At this point, I'm less worried about somebody getting access to some random startup I signed up for than I am about them using the leaked password to gain access to my other accounts.
(I've recently changed my password scheme to using a different one for every service, but this just puts me within a minority.)
Doesn't http://en.wikipedia.org/wiki/Digest_access_authentication do this? Also the server could store the nonce in a session.
If the salt is stored on the server, in a login.php script for example, and there is (just) a database compromise then an attacker will be at a disadvantage because they will need to figure out the salt first before cracking any of the passwords.
In fact, this is something being ignored here quite a bit. A number of potential attacks only lead to the database - or part of it - being exposed. If you have a large enough salt stored in your unaffected code base then an attacker is going to have a hard time.
I note that the question was migrated from StackOverflow to security.stackexchange.com. After all, this is an issue that the security nerds care about. Why bother ordinary developers with it? </sarcasm>
Following your train of though, we should display the salt and the hash publicly. That is extremely dumb.
Put your passwords in your post, otherwise you'll be doing security through obscurity! oh snap?
If you use a "clever" scheme to store / generate your salt, you make your system more complex in an attempt to hide something that does not really need to be hidden. You might also end up introducing implementation flaws.
That's why bcrypt uses nonces for its salts, and simply appends them to the encrypted passwords.
Also see http://en.wikipedia.org/wiki/Kerckhoffs%27s_Principle
Basically, the site would have a copy of my public key (say my GPG key or an ssh key), and to authenticate I prove that I have access to the corresponding private key.
http://googleblog.blogspot.com/2011/02/advanced-sign-in-secu...
yet my bank's web site, not so much.
What I was talking about was something different. Public/private key encryption where only the public key is stored on the server.
Here's an example scenario: the server generates a random pass-phrase then encrypts it using the public key. The end-user then uses their smartphone where the private key is stored to decrypt the message and return the original pass-phrase back to the server, proving they have the private key. There are similar ways of achieving a similar result that are less cumbersome and awkward. The advantage is that if the public key is leaked it's not a big deal, it can't be used to gain access to the system.
What do you do when you loose the keys?
You don't. And ideally you have a single key. If you can be trusted to keep a social security card and a passport, you can just as easily keep a key safe. Print it out. Store it in a safe place. We've been doing that for centuries. And the default behavior or enabling keys whenever your computer is open?
You can password protect your keys.If someone steals your passport, you'll know: you won't be able to find it.
Digital keys have no such properties. If someone steals your private key, you will have no idea until you see them steal all your money and accounts.
Physical items also need to be carried to a destination to be used. If someone steals your passport, they may be able to take over your bank accounts, etc. For that, they have to actually go in person to meet a bank manager and pretend to be you. People do that fairly successfully, but it's hardly an efficient process.
A digital passport/key, on the other hand, could be abused immediately after it's been stolen, and could be used across all your accounts within the hour, before you've even realised you've been robbed.
Finally, you can only use one passport at a time. Not only it takes time, but you need a career criminal dedicated to each "process".
A digital key robbery, however, requires no human element, and thus can be done in parallel at a large scale. One could use Trojans to capture the keys of a large number of people and steal their money in an automated manner without ever showing up at a bank.
All those problems can perhaps be solved, but they are not easy and they have nothing to do with keeping the key safe - more to do with keeping the process of using the key as inefficient as possible. The best way to ensure your digital key cannot be abused is to make sure that you can only use it in person in front of other human beings, on authorised hardware.
So, pretty much like the way our bank cards work, then.
In a couple of years everyone will have on of those cards, the problem is that nobody has readers.
1. http://www.independent.co.uk/news/uk/home-news/clone-wars-mo...
2. http://www.expatsvoice.org/forum/showthread.php?t=7001
I guess that Mossad can gather the information needed to clone a passport in under half a minute.
So while I agree that the analogy between key reminder and password is not perfect, the point is basically sound.
(On rereading your post, your point [p]hysical items also need to be carried to a destination to be used made me realise that I might have misunderstood the point you were making, but also that you may have misunderstood the point ihodes was making).
There's an addon for Firefox called Enigform (I've not tried it out yet) which uses PGP for web authentication:
But the worse GUI is arguably better than no GUI at all:
http://code.google.com/p/android/issues/detail?id=8196 and http://stackoverflow.com/questions/357491/iphone-client-cert...
So, for the purposes of the growing mobile browser market (where having this would be the biggest benefit IMO), this is not applicable.
Which is a bit unfortunate.
Your answer was right, it stores the work factor, the salt and the hash so that at any given time you can change the work factor and it will adjust in the database!
Assuming you're using a secure connection and you're willing to send plaintext passwords over it then yes, you could re-hash the password when a user logs in.
[1] http://en.wikipedia.org/wiki/Zero-knowledge_password_proof [2] http://en.wikipedia.org/wiki/Secure_remote_password_protocol
Various schemes introduce a client nonce and server nonce (to prevent man-in-the-middle attacks) or generate a shared secret nonce through methods similar to the Diffie-Hellman key exchange (so attackers can't work out the nonce).
[1] Ensure that h(h(passwd)+nonce) is equal on both ends where h(passwd) is either stored (server) or created by the user providing the plaintext password.
[2] http://en.wikipedia.org/wiki/Challenge-response_authenticati...
In this model, the server would receive the (unsalted) hash of the password when the password is set, and a salted hash for each login. At no point will the server ever have the plaintext password.
I describe the implementation details here:
Also, if you're storing the unsalted hash in your DB, your security is doubly broken. Someone who accesses your DB can more easily brute force the passwords (it looks like you're using a single salt rather than a per-user salt), and your scheme is vulnerable to rainbow attacks as well.
https://github.com/rails/rails/blob/master/activemodel/lib/a...
How does a server authenticate users in high volume with bcrypt? ~0.25 secs per auth request might warrant having a separate server just for authentication.
Note that bcrypt is basically insensitive to length of password. 4 chars, 8 chars, 32 chars, all take the same amount of time. And it's tunable. You could go down to only 0.01s per hash and still be a million times slower than plain MD5.
Part of its beauty is you can adjust the work factor to match your hardware speed requirements.
If you really want ultra-secure, a work factor is 13 is getting pretty slow (about half a second per hash on my crappy machine), and yeah, that might justify an authentication server.
(note: my tests were not exhaustive)
Bcrypt at 10ms is 3 million times slower, not 300 times.
So I'm comparing the fastest you can do bcrypt hashes (100 a sec at that work factor) vs the fastest you can do MD5 hashes (250 million per second)
However, after logging in and establishing a session, there's really no impact to the user. We were content to trade the speed of lesser hashing algorithms for the security offered using bcrypt. The only noticeable difference is that our login process went from near-instantaneous to a marginal, but noticeable delay, on login.
(The same delay can be noted when setting new passwords.)
I'm sold on bcrypt but like to hear scaling stories :)
Users (usually) need to login only once per session. And on sites that have the little "Remember me"-tickbox a session may very well last for days or even months.
I would think that using bcrypt for authentication would not only consume more server CPU power, but would also open the door to denial-of-service attacks (if crackers attempted brute-force attacks on the log-in system). Clearly "use bcrypt" is just part of the answer...
I had some thoughts on a way to deal with this:
http://news.ycombinator.com/item?id=2705915
(but my ideas have their own set of problems.)
Disadvantage: Clients need to have JavaScript enabled.
http://news.ycombinator.com/item?id=601408
I would have loved to use scrypt, but there is only a C implementation. I would had loved to have at least a javascript one.
This means that you essentially have to make your KDF's workload much weaker than if you used C implementation to get an acceptable performance.
The only reason GPUs are cited as testing 600 million hashes a second is that the underlying hashes came from a Microsoft Windows Active Directory where they were simply MD4 encoded. That speed is not possible with bcrypt. Devs need to understand this.
Edit: Yes, that's MD4 not MD5. Microsoft Windows NT hashes are simply Unicode strings that are MD4'ed. This includes Windows 7 and Windows 2008 server.
If you consider the loss of business to be pretty much constant in the event of a loss of control of the customer's data, what is the value of extra server(s) (plus the cost of maintenance) for one of the least valuable pieces of information a customer can give you?
As an example, look at Instapaper. How many people are more concerned that the government has access to their sha1 encrypted passwords as opposed being concerned that the government has free access to their reading history?
Obviously they It's up to you whether you care enough about your customers to try to get security right. You gave a reasonable argument for why using bcrypt instead of md5 makes little financial sense. However, that same argument applies to plaintext vs hashed. Or hashed vs hashed with salt. In the end, you need to decide how much you care about security, and also weigh how much security you are morally obligated to provide.
And while I may feel morally obligated to provide great security, the people I report to would not be as impressed with that in a cost-benefit analysis.
tl;dr It's a great idea, but a tough sell, particularly at scale.
I can't imagine how "good security - scalable enough for Twitter" can be a hard sell. Your customers certainly won't by sympathetic if they learn that you willfully chose weaker security to save a buck.
With a work factor of 7, hashing might take around 10ms. Which is not a whole lot, but much, much more secure than MD5 and SHA1.
The attack is done by getting a list of plain text passwords and then running them through the same hashing algorithm as was used originally (adding the salt value if present). Once the attacker has done that they just compare the hashed strings. If they match then it'll be the same password.
Commonly the attacker would start with a dictionary of common passwords and submit them along with common variants (eg, password, Password password1 passw0rd).
If that's not successful they can move onto pure brute force (eg, a , ab, ac, etc)
the salt is not "secret" - it is stored in plain text for each password. it does not need to be secret to do its job (defend against rainbow tables).
If the only attack situation you're worried about is a online guessing attack, then there's no need to even hash passwords.
That isn't the problem. Reuse is. And the best way around that is to not let the user select the password, just generate it server side. Technically this is easier to get right than some complex password generation scheme and the end result is properly better too.
Generating server-side passwords is horrible as well since you're counting on the user to write it down and/or let the browser's password manager save it. What if the user wants to log in with a different machine/browser?
I think the best solution is to, first, forbid passwords under 10 characters. 8 is still relatively secure, but not really, 10 at least gives you a fighting chance. Second, run your own dictionary attack (you can load /usr/share/dict/words into a hashtable and check for membership in sub-second times..in fact, here:
import sys
f = open('/usr/share/dict/words')
words = {}
for line in f:
words[line.replace('\n','')] = None
if sys.argv[1] in words:
print 'You fail'
) and alert the user if their password sucks and to pick a new one. (You might want to check for membership of their password with an 's' or a '1' or something added on as well.) You might also want to do some sort of complexity analysis as well that requires e.g. at least one uppercase, one lowercase, one number.The infrastructure problem is places like Banks saying "Enter a password between 6 and 12 characters and only use alphanumeric characters!"
That unfortunately puts a lot of confidence in the security of the sites that you give your password to. Your super safe password is not that safe if a site stores it as plaintext or MD5 and it gets hacked.
Otherwise I agree with your comment.
I used a method a few years ago to generate passwords for users on an intranet. They were free to replace them, but a poll showed that most users went with the suggested password. I focused on generating passwords that users could pronounce (and therefore remember), like gekava86, lofesu75, 23wopeni, etc.
At the time, I didn't use BCrypt so they were a bit weak (though certainly stronger than whatever the users' regular password was). If you use BCrypt, you don't have to worry as much about the password being "strong", the focus comes back to it being unique.
So the problem is that passwords tend not to be random. This greatly decreases the problem-space. But b/scrypt solves the problem of length, within reason.
For instance, a plain alphanum password of length 9 is stronger than a password of length 8 that allows for special characters. (because 62^9 > 94^8)
In other words, adding one character to your password is as good as choosing from a bigger character set.
Okay, beginning at length 10, you'd need to add two characters, but that's really all you need to do up to length 20. (which is an insane length for a random password anyway)
Using punctuation does not make a password "more random", it only makes the random choice set slightly larger. Bumping the length is much more significant than bumping the set as it's exponential.
The debate is whether it's easier for a user to both pick and remember a "random-enough" - i.e not easily bruteforce-able, regardless of hashing technology - [A-Za-z]{10} password or a [A-Za-z0-9!@#$%^&()_-+=;':",.<>/?\|[\]{}]{8} password.
For the record, Google's 2-factor auth generated app-specific passwords are [a-z]{16}, which gives 1E22, or 230 billion years with bcrypt at 0.3s.
This is why MD5 is not a good password-based key derivation function. :-)
with open('/usr/share/dict/words') as wordlist:
words = set(line[:-1] for line in wordlist)
Or, for one time check you can stop reading on match: import sys
lookup = '%s\n' % sys.argv[1]
with open('/usr/share/dict/words') as wordlist:
[ sys.stdout.write('Dictionary password: %s' % lookup) or sys.exit(1) for line in wordlist if line == lookup ]
As for the objective, this checks only exact dictionary matches. In real world, you'd use cracklib to check any dictionary based or weak passwords rather than reinvent the wheel. See http://gdub.wordpress.com/2006/08/26/using-cracklib-to-requi... import sys
lookup = '%s\n' % sys.argv[1]
with open('/usr/share/dict/words') as wordlist:
for line in wordlist:
if line == lookup:
sys.stdout.write('Dictionary password: %s' % lookup)
sys.exit(1) import pickle
# initialize:
wordset = frozenset(line.lower().rstrip() for line in open('/usr/share/dict/words'))
pickle.dump(wordset, open('/tmp/wordset.pkl', 'wb', -1))
# when you want to use it:
wordset = pickle.load(open('/tmp/wordset.pkl', 'rb'))
'bear' in wordset # == True >python wordlist.py -w wordlist -p wordlist.pkl
>python wordlist.py -T wordlist wordlist.pkl 10 3
2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]
words(wordfile): 142.50 best msec/loop
words_slower(wordfile): 161.00 best msec/loop
words_normalized(wordfile): 295.84 best msec/loop
words_pickled(pickled): 2943.66 best msec/loop
The winner is: with open(wordfile) as wordlist:
return frozenset(wordlist.read().split('\n'))
Source: https://gist.github.com/1059725Wordlist: http://www.freebsd.org/cgi/cvsweb.cgi/src/share/dict/web2?re...
Do you have different results?
https://github.com/search?q=password+strength https://sun.athnic.net/password-test.html http://www.geekwisdom.com/dyn/passwdmeter http://cafewebmaster.com/check-password-safety-javascript-wh...
Depending on the attack scenarios, that may not actually be more risky than allowing users to choose their own password..
I'd say that the best compromise of these approaches would be to encourage the use of password safe programs which at least store the password list in an encrypted format on local machines (of course this still relies on the user choosing a strong password for the password safe..)
Assuming the attacker brute-forces all 3 word combinations, maybe. But "fluffy is puffy" is a valid English sentence and language is a rather poor source of entropy.
Can I increase the work factor of an existing hash, or must I wait until the user logs in and then use the plaintext password to generate a new hash?
Is there a bcrypt API that provides a hash comparison function that addresses timing attacks? The py-bcrypt example code uses the '==' operator to compare hash strings, leaking timing information:
# Check that an unencrypted password matches one that has
# previously been hashed
if bcrypt.hashpw(password, hashed) == hashed:
print "It matches"
else:
print "It does not match"
(from http://www.mindrot.org/projects/py-bcrypt/)1) Take those md5 unsalted passwords and 2) bcrypt them
Then upgrade the users to non-pre-hashed bcrypt as they log in?
?
Learning how to separate good from bad advice is a skill that needs to be maintained. Also, in all software that is supposed to provide some form of security, one has to be prepared for the eventuality that it probably contains errors.
I used to read a lot of books on cryptography and the use of cryptography. I've forgotten most of it by today, and to be quite frank: the more I know, the less I want to write crypto software. There is something deeply unsatisifying about work where you know that what will in all likelihood trip you up is some trivial, stupid mistake.
It isn't hard because of the crypto itself. Sure, certain cryptographic libraries can be extremely awkward to use (which in itself is a security risk), but the problem usually comes from where you aren't looking for them.
I cringe a bit when people advertise software as being secure because it uses this or that encryption scheme. I also cringe when people claim that they "encrypt databases" and their systems are therefore secure -- because, for most usage scenarios, I can't think of any really secure way of doing this. Not without compromises anyway. And while I honestly know that I have just a rudimentary grasp on cryptography, I know a lot more about it than most people who make products that hinge upon correct application of crypto.
Just the other day I was trying to determine how many rounds I wanted to use in bcrypt for storing passwords for a given system. I think I spent most of the day pondering this question, writing benchmarks and reading up on what other people said on the topic. A couple of days later a friend of mine emailed me a code snippet that implemented the password hashing scheme of a commercial product they use that makes shameless claims about being secure. (I think he probably just looked at the hashed passwords and made a guess about the method they had used. I don't think he had a look at the original source code). If memory serves the product uses unsalted SHA1 hashing. In other words, the vendor didn't even bother thinking about the problem.
What scares me a bit is that even I thought "well, if they claim to have well thought-out password handling and they are in the business of selling security systems, I suppose they have probably given this a lot of thought" the first time I visited their website. After all, large companies give them millions. Right?
I wonder what other things they are doing equally badly.
Similar discussion: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the...
function(uniqueSalt128Bit, password, rounds) {
var hash = SHA1(uniqueSalt128Bit + password);
var length = Math.pow(2, rounds);
while (length--) hash = SHA1(hash);
return hash;
}That said, there's nothing wrong with choosing another password derivation scheme. glibc's crypt() provides three: PHK's MD5 scheme, and Ulrich Drepper's stretched SHA-{256,512}. Just don't roll your own and you'll be ahead of the majority of programmers.
The only reason you would want to use PBKDF2 is if (a) you already have a hash and don't want to add blowfish to your code/circuit, or (b) you want to be standards-compliant.
http://msdn.microsoft.com/en-us/library/system.security.cryp...
Make sure to use the defaults or better in terms of rounds. The salt provided when you don't supply one is cryptographically random.
But the alternative seems to be to make every request very slow, because it would require bcrypting the password with every request.
I suppose you could come up with some scheme where you create a new cookie with every request, a kind of one-time cookie to prevent session hijacking. Probably not worth it and not 100% reliable, though.
I guess just trusting in cookies is the only real option.
Or HTTP BasicAuth, it sends the password with every request I think (unencrypted, I know). In either case in theory you need HTTPS.
Otherwise, you're just trolling, and I've committed a cardinal sin.
eight characters is easy - try cracking 50
True.
This isn't meant for the user, though. This is meant for the developers. No matter how hard the developers try, users will always pick bad passwords. If you use salted SHA-1, then if the database gets compromised there goes 50% of the passwords. If, on the other hand, you use bcrypt, maybe only 5% of the passwords get cracked.
Bcrypt turns a massive news event (database leaked; thousands of passwords lost!) in to something much less newsworthy (database leaked; twenty passwords lost).
The only reason why bcrypt is better than PBKDF2 is that blowfish needs a large circuit to compute.
Maybe it should be optional?
HN is better without karma, just think of it as a place to find out about concepts you might not have been aware, then drill down on it with some more trusted source.
If someone managed to break in to your website and get the password hashes, chances are they also have your "secret" salt. There is no reason to separate the salt from the hash, and, in fact, there are no implementations which do that.
However, if I can't convince you of that, then if you ever make a website that takes passwords, please use bcrypt. You can do your super-special-salt-separation-scheme, but just use bcrypt instead of SHA-1.
I believe the GP was referring to the scheme where you don't store the salts at all (or only store some bits of each salt.) The verification needs to brute-force the salt (or the missing bits) each time it verifies the password.
The missing bits are quite similar to the bcrypt workfactor - the more you leave out the harder it is for both the attacker and the legitimate verification to verify passwords.
If it is derived in code from some other piece of user data then it is still "known" if your DB leaks - you have to assume someone who stole your database also stole your code.
Maybe, but that doesn't mean that a separate salt, not in the database, will prevent certain attacks, and as such is a viable option. Security is about layering, not about 'xyz isn't 100% secure in 100% of the cases, forget about it'.
"sha1 with a salt u cant find beats bcrypt with a key u know any day"
This is fractally wrong.
It brute forces the missing part. Obviously you may only leave out a number of bits that keeps it feasible.
Anything you can brute force with your hardware can be brute forced on someone else's hardware.
How doesn't this argument apply to increasing work factor in bcrypt?
The primary reason I think your idea isn't favorable to using bcrypt is because of the weight of experience and research. Dropping bits from your salt might be a perfectly valid crypto protection technique, but when it comes to crypto, I'm inclined to go with research over cleverness.
If dropped bits from the salt were a viable means of securing passwords, I'd imagine that someone would have implemented something like this already. It's one of those "oh, that's clever" ideas, but the cleverness trap is a dangerous thing. Just because something is clever doesn't make it good.
This is one of the most oft repeated warnings when it comes to crypto: don't build your own, you'll do it wrong.