Commit 63d6a50d authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #18144 -- Added backwards compatibility with old unsalted MD5 passwords

Thanks apreobrazhensky at gmail.com for the report.
parent ace9d4ef
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -132,7 +132,8 @@ def identify_hasher(encoded):
    get_hasher() to return hasher. Raises ValueError if
    algorithm cannot be identified, or if hasher is not loaded.
    """
    if len(encoded) == 32 and '$' not in encoded:
    if ((len(encoded) == 32 and '$' not in encoded) or
            len(encoded) == 37 and encoded.startswith('md5$$')):
        algorithm = 'unsalted_md5'
    else:
        algorithm = encoded.split('$', 1)[0]
@@ -372,6 +373,8 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
        return hashlib.md5(force_bytes(password)).hexdigest()

    def verify(self, password, encoded):
        if len(encoded) == 37 and encoded.startswith('md5$$'):
            encoded = encoded[5:]
        encoded_2 = self.encode(password, '')
        return constant_time_compare(encoded, encoded_2)

+5 −0
Original line number Diff line number Diff line
@@ -66,6 +66,11 @@ class TestUtilsHashPass(unittest.TestCase):
        self.assertTrue(check_password('lètmein', encoded))
        self.assertFalse(check_password('lètmeinz', encoded))
        self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5")
        # Alternate unsalted syntax
        alt_encoded = "md5$$%s" % encoded
        self.assertTrue(is_password_usable(alt_encoded))
        self.assertTrue(check_password('lètmein', alt_encoded))
        self.assertFalse(check_password('lètmeinz', alt_encoded))

    @skipUnless(crypt, "no crypt module to generate password.")
    def test_crypt(self):