> Lest a user submit a 50,000 character password?
What's wrong with that?
Edit: Hunh, apparently bcrypt only handles 72 chars anyways.
Exactly. You aren't storing those bytes.
> Maybe not an issue for a 50k char password, but how about a 50 billion char password?
We're back to a place where the response to the question is another question, but it just ends up failing to give an answer, opting to just keep throwing out larger and larger numbers. My response: "Yeah, okay. How about it?" Why stop at 50 billion? 99 trillion, let's go there next. Again: why not?
Because 50 billion chars is over 46 GiB of data. There are natural consequences of very large payloads and limits that you're going to reach as a result of those consequences (e.g. being prohibitively expensive for the client to send in the first place, or it will max out the server's connectivity lifetimes for extant requests before the payload can be delivered). If "CPU utilization crosses threshold" is the real reason, then let that be the real reason—and let the safeguards you have in place for handling those problems do their jobs. And if "we cap passwords to X chars" is your safeguard, then you have bigger problems.
To me, this feels a bit like passing the buck.
If you want to test your backend with 50-billion-character passwords as a safeguard in case things get screwy, that makes sense to me! But, has that test been done? Are you sure?
I see this as analogous to the concept of "defense in depth". Safeguarding against very weird edge-cases which do not provide utility to anyone is a good idea. If you assume the other part of the chain can deal with it, and you're wrong, things blow up. If you assume the worst, all will be well regardless.
[1] To that point, most people want to spend time on useless optimizations like truncating a password when they should be spending time reducing the size of their images, making sure requests are gzipped, or reducing their obscenely complex front-end bundle. It's just that most of those optimizations which are useful, only make you feel stupid for not implementing them sooner because they're obvious and easy, while truncating a password feels like YOU outsmarted something (when in fact you didn't)
More importantly though, a 50k character password is barely more secure than a 20 character one, but it gives the user a false sense of security. Passwords are inherently flawed and we shouldn't kid ourselves that just making them longer makes a difference.
If you're in a situation that calls for a 2^400 keyspace, you probably shouldn't be using passwords anyways.
You're probably thinking 50MB. Hashing 50kB should be almost instantaneous.
That being said, I just ran a very simple test with just sha256sum and broke 0.3s only at 32MiB, so either crypt() is doing much more than I tought (is salting _that_ expensive?) or I am reading that post completely wrong.
It should give you much more than that, considering that the green (SHA256) graph hits almost 0.1s at just 1000 bytes of input.
>either crypt() is doing much more than I tought (is salting _that_ expensive?)
glibc crypt() is probably doing more than you thought, but it's not salting: in SHA256 mode, various combinations of the key and intermediate hash digests are repeatedly hashed in a certain pattern for 5000 times, although the number of rounds can be changed just like the hashing algorithm. (This is a glibc implementation detail; not all crypt() implementations support extensions like SHA256 mode.)
In general, all general purpose cryptographic hash functions are reasonably fast.
Thanks for the info on what crypt() actually does. I definitely need to look into that some more...
Also many bcrypt implementations truncate input longer than 72 characters.
It should be though, the backend should reject overlong passwords, and the frontend should have such limits as well.
Though by "overlong" I mean kbyte range, not 32 character. The point of the limitation is to avoid randos feeding megabytes of data into your KDF and DOSing your server.
> Also many bcrypt implementations truncate input longer than 72 characters.
The alternative would be to error as bcrypt works on 18 words (of 32 bits). You need special handling (pre-hashing with a non-broken cryptographic hash function) to fix this issue.
Also it's 72 bytes not characters. And your pre-hash needs to generate some sort of textual representation (hex, base64, base85, …), as bcrypt will also truncate at the first NUL byte.
The original paper actually specifies 56 bytes.
> The point of the limitation is to avoid randos feeding megabytes of data into your KDF and DOSing your server.
You shouldn't be using a KDF that takes significantly longer when the password gets bigger. If you make that mistake, even a kilobyte is going to be annoyingly slow. If you don't make that mistake, then even MAX_POST_SIZE passwords won't DOS you.
Your KDF necessarily takes longer when the password gets longer as it's a hash function and thus O(n).
For typical password sizes (typically under 64 bytes), you're below the hash's blocksize so the effect is nil and you can treat it as a constant but it will start coming into play as the size of the key and thus the number of blocks to feed into the hash increases.
If adding a megabyte of input causes the original megabyte to get hashed or otherwise processed once, then you pass the test.
If adding a megabyte of input causes the original megabyte to get fed into your algorithm 100000 times, then you fail the test.
If you're really paranoid about cryptography then reject it. If you're slightly less paranoid then pass it through SHA512 before bcrypting it. Never silently truncate a password.
In any case this doesn’t preclude client-side validation.
Two weeks later, an angry user (the only one with a 100-digit password) complains that they can't log in anymore. The guy is the company's best-paying customer; the boss is furious. The whole team goes on a wild goose chase for two days and nights just to find out what happened, as clearly there's nothing wrong with their code.
A few years later, a former colleague shares the episode on HN. As you read the comments, it dawns on you that the idiot antagonist of the story is you. In this moment, you are enlightened.
If you switch to a different bcrypt implementation that does/does not truncate at 72 characters, the server-side truncation keeps all those 73 character passwords working.
If the server-side truncation were not in place, you'd get angry users.
But it's the same principle no matter where you cut. User thinks they can use an arbitrarily long password, puts a long but low entropy or easily guessable string at the front and makes up for it by having some good entropy at the end, and then you chop off the end.
I welcome responses explaining why passwords of hundreds of characters would ever be necessary or useful.
So long as you're using a password manager that generates unique passwords for every site you visit, there's no real reason to have those generated passwords be particularly long. Ten random characters (with enforced complexity rules) is more than ample for any normal, plausible scenario. If you're a high value individual, you might want to eliminate any doubt and use 12–15 characters. Exceeding that is security masturbation—but also lacks any downside so long as you never have to transcribe it.
Or if you fear worldwide retribution, 20 characters is enough to withstand all compute power on earth suddenly dedicated to the task of cracking your Spotify password.
The only scenario I can imagine where the length of random+unique passwords matters AT ALL is if (1) the website uses a very weak/naive password hash implementation (2) a hacker manages to acquire a copy of your hashed password and (3) the account is of sufficiently high value to justify a large investment in computing resources to brute force the hash. Hitting that trifecta is very unlikely indeed.