From 1b048618e0417f7b2d7d43fc657424fe9bd1988f Mon Sep 17 00:00:00 2001 From: bliepp <12013202+bliepp@users.noreply.github.com> Date: Sun, 25 Sep 2022 13:47:59 +0200 Subject: [PATCH 1/2] Allow overriding _handle_long_passwords --- flask_bcrypt.py | 16 ++++++++++++---- test_bcrypt.py | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/flask_bcrypt.py b/flask_bcrypt.py index 994985a..2d4ffb2 100644 --- a/flask_bcrypt.py +++ b/flask_bcrypt.py @@ -163,7 +163,7 @@ def _unicode_to_bytes(self, unicode_string): bytes_object = unicode_string return bytes_object - def generate_password_hash(self, password, rounds=None, prefix=None): + def generate_password_hash(self, password, rounds=None, prefix=None, handle_long_passwords=None): '''Generates a password hash using bcrypt. Specifying `rounds` sets the log_rounds parameter of `bcrypt.gensalt()` which determines the complexity of the salt. 12 is the default value. Specifying `prefix` @@ -178,6 +178,7 @@ def generate_password_hash(self, password, rounds=None, prefix=None): :param password: The password to be hashed. :param rounds: The optional number of rounds. :param prefix: The algorithm version to use. + :param handle_long_passwords: Enable prehashing with SHA256 ''' if not password: @@ -192,14 +193,17 @@ def generate_password_hash(self, password, rounds=None, prefix=None): password = self._unicode_to_bytes(password) prefix = self._unicode_to_bytes(prefix) - if self._handle_long_passwords: + if handle_long_passwords is None: + handle_long_passwords = self._handle_long_passwords + + if handle_long_passwords: password = hashlib.sha256(password).hexdigest() password = self._unicode_to_bytes(password) salt = bcrypt.gensalt(rounds=rounds, prefix=prefix) return bcrypt.hashpw(password, salt) - def check_password_hash(self, pw_hash, password): + def check_password_hash(self, pw_hash, password, handle_long_passwords=None): '''Tests a password hash against a candidate password. The candidate password is first hashed and then subsequently compared in constant time to the existing hash. This will either return `True` or `False`. @@ -212,13 +216,17 @@ def check_password_hash(self, pw_hash, password): :param pw_hash: The hash to be compared against. :param password: The password to compare. + :param handle_long_passwords: Enable prehashing with SHA256 ''' # Python 3 unicode strings must be encoded as bytes before hashing. pw_hash = self._unicode_to_bytes(pw_hash) password = self._unicode_to_bytes(password) - if self._handle_long_passwords: + if handle_long_passwords is None: + handle_long_passwords = self._handle_long_passwords + + if handle_long_passwords: password = hashlib.sha256(password).hexdigest() password = self._unicode_to_bytes(password) diff --git a/test_bcrypt.py b/test_bcrypt.py index 0ec2ffe..822624b 100644 --- a/test_bcrypt.py +++ b/test_bcrypt.py @@ -64,6 +64,15 @@ def test_long_password(self): # Ensure that a longer password yields the same hash self.assertTrue(self.bcrypt.check_password_hash(pw_hash, 'A' * 80)) + def test_custom_long_password(self): + """Test the work around bcrypt maximum password length when set explicitly.""" + + # Create a password with a 72 bytes length + password = 'A' * 72 + pw_hash = self.bcrypt.generate_password_hash(password, handle_long_passwords=True) + # Ensure that a longer password yields the same hash + self.assertFalse(self.bcrypt.check_password_hash(pw_hash, 'A' * 80, handle_long_passwords=True)) + class LongPasswordsTestCase(BasicTestCase): @@ -83,6 +92,15 @@ def test_long_password(self): # Ensure that a longer password **do not** yield the same hash self.assertFalse(self.bcrypt.check_password_hash(pw_hash, 'A' * 80)) + def test_custom_long_password(self): + """Test the work around bcrypt maximum password length when set explicitly.""" + + # Create a password with a 72 bytes length + password = 'A' * 72 + pw_hash = self.bcrypt.generate_password_hash(password, handle_long_passwords=False) + # Ensure that a longer password yields the same hash + self.assertTrue(self.bcrypt.check_password_hash(pw_hash, 'A' * 80, handle_long_passwords=False)) + if __name__ == '__main__': unittest.main() From 81536dc662d0da813bdbd2154ac21eb2ef380921 Mon Sep 17 00:00:00 2001 From: bliepp <12013202+bliepp@users.noreply.github.com> Date: Sun, 25 Sep 2022 17:59:10 +0200 Subject: [PATCH 2/2] Fix typos in test comments --- test_bcrypt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_bcrypt.py b/test_bcrypt.py index 822624b..5355e39 100644 --- a/test_bcrypt.py +++ b/test_bcrypt.py @@ -65,12 +65,12 @@ def test_long_password(self): self.assertTrue(self.bcrypt.check_password_hash(pw_hash, 'A' * 80)) def test_custom_long_password(self): - """Test the work around bcrypt maximum password length when set explicitly.""" + """Test the work around bcrypt maximum password length when set explicitly to True.""" # Create a password with a 72 bytes length password = 'A' * 72 pw_hash = self.bcrypt.generate_password_hash(password, handle_long_passwords=True) - # Ensure that a longer password yields the same hash + # Ensure that a longer password *does not* yield the same hash self.assertFalse(self.bcrypt.check_password_hash(pw_hash, 'A' * 80, handle_long_passwords=True)) @@ -89,11 +89,11 @@ def test_long_password(self): # Create a password with a 72 bytes length password = 'A' * 72 pw_hash = self.bcrypt.generate_password_hash(password) - # Ensure that a longer password **do not** yield the same hash + # Ensure that a longer password **does not** yield the same hash self.assertFalse(self.bcrypt.check_password_hash(pw_hash, 'A' * 80)) def test_custom_long_password(self): - """Test the work around bcrypt maximum password length when set explicitly.""" + """Test the work around bcrypt maximum password length when set explicitly to False.""" # Create a password with a 72 bytes length password = 'A' * 72