BCrypt effectively limits password length.
Bcrypt effectively truncates the password if it goes over a certain threshold. With the default configuration of Django that seems to be 72 characters. I propose adding a new hash backend that first hashes the password using SHA512. This will not negatively affect the strength of the password hash because bcrypt(sha512(plaintext)) is not insecure as long as sha512 isn't broken. More information: http://security.stackexchange.com/questions/6623/pre-hash-password-before-applying-bcrypt-to-avoid-restricting-password-length .
>>> import random, string, hashlib
>>> from django.conf import settings
>>> settings.configure()
>>> from django.contrib.auth.hashers import BCryptPasswordHasher
>>> password = "".join(random.choice(string.ascii_uppercase + string.digits) for x in range(100))
>>> bcrypt = BCryptPasswordHasher()
>>> bcrypt.verify(password, bcrypt.encode(password, bcrypt.salt()))
True
>>> bcrypt.verify(password[:72], bcrypt.encode(password, bcrypt.salt()))
True
>>> bcrypt.verify(password[:71], bcrypt.encode(password, bcrypt.salt()))
False
>>> bcrypt.verify(hashlib.sha512(password).digest(), bcrypt.encode(hashlib.sha512(password).digest(), bcrypt.salt()))
True
>>> bcrypt.verify(hashlib.sha512(password[:72]).digest(), bcrypt.encode(hashlib.sha512(password).digest(), bcrypt.salt()))
False
>>> bcrypt.verify(hashlib.sha512(password[:71]).digest(), bcrypt.encode(hashlib.sha512(password).digest(), bcrypt.salt()))
False
Change History
(4)
Resolution: |
→ fixed
|
Status: |
new → closed
|
The length of a sha512 digest is 64 bytes so it's within the limit of bcrypt, although even if it wasn't it wouldn't much matter because it retains the property that a small change in the input (the password being truncated) results in a large change in the output.