I'm not entirely opposed to requiring a minimum length, but imposing max lengths / character class rules / etc ends up hurting people who want to pick strong passwords more than it helps people who would pick weak ones (enforcing character classes just gets us lots of password1A! and similar)
I think that this is a good balance between security for short passwords, while still allowing ridiculously long ones (pass-phrases).
[1] http://arstechnica.com/security/2014/04/stanfords-password-p...
8 random upper/lower/digit/symbol characters are equal to 9 random mixed-case letters. Not 16.
Their cutoffs for different mixes are 8, 12, 16, 20. Realistic cutoffs would look more like 10, 11, 11, 14.
Even worse, they encourage counting the individual letters in words. Never do that. Random words are only as good as two random characters.
$ dd if=/dev/urandom bs=32 count=1 | xxd -p
That nearly every site on the Internet will refer to that output as "not strong enough" and instead suggest P@ssword1 as a better alternative definitely speaks to the issue.I have implemented that on a site. It wouldn't accept the top 10,000 most common passwords. (or was it 1k).
Otherwise ~1% of your users will pick "password" as a password.
It's now in django[0]. And it's a hoot to read...
[0] https://github.com/django/django/blob/master/django/contrib/...
I would however suggest trimming trailing spaces.
Also, for a nicer user experience try the password twice: As is, and with case reversed. This lets people login even with capslock on and has little impact on security (i.e. don't be case insensitive! just case reversed.)
I do like the idea of warning the user upon creation.
For instance, the German sharp s (ß) has an asymmetrical casemapping.
From the Unicode standard[0]:
>The German sharp s character has several complications in case mapping. Not only does its uppercase mapping expand in length, but its default case-pairings are asymmetrical. The default case mapping operations follow standard German orthography, which uses the string “SS” as the regular uppercase mapping for U+00DF ß latin small letter sharp s. In contrast, the alternate, single character uppercase form, U+1E9E latin capital letter sharp s, is intended for typographical representations of signage and uppercase titles, and in other environments where users require the sharp s to be preserved in uppercase. Overall, such usage is uncommon. Thus, when using the default Unicode casing operations, capital sharp s will lowercase to small sharp s, but not vice versa: small sharp s uppercases to “SS”, as shown in Figure 5-16. A tailored casing operation is needed in circumstances requiring small sharp s to uppercase to capital sharp s.
[0] http://www.unicode.org/versions/Unicode7.0.0/ch05.pdf#G21180
As they say "so don't do that".
This is about capslock, not lettercase in general. Only switch characters that change with capslock on the keyboard.
And even if the mapping is not perfect - so what? The worst that will happen is nothing.
In that case you'll want to pre-hash your BCrypt-encoded passwords, otherwise you'll be imposing a silent 72 character limit.
Remember to encode the hashes, since BCrypt also silently truncates after NULL bytes.
Or just use PBKDF2 or scrypt, neither of which imposes an artificial length limitation on passwords.
Not that it really matters, since a 72-character password will have hundreds of bits of entropy as long as the alphabet is more than two characters; it's overkill.
Or XKCD style passphrases. Using the Oxford 3000 dictionary gets you about 1 bit of entropy per character. If I have my password manager generate 128 bit passphrases using them for ease of use in the real world, plain bcrypt will quietly reduce their strength by about 17 orders of magnitude. If nothing else that's obnoxious.
And that's ignoring the soft 55 byte limit both the bcrypt spec and the original scrypt paper mention. If we're looking at less than one bit per byte that's starting to get into worryingly weak territory.
Either way, it's all solved by stuffing a (e.g.) base64 SHA384 in there. Bam, every input bit equally effects the output hash regardless of length and position, and the entire thing even becomes NULL byte safe.