From 418c9f3fe5d8359f6c77813a2902e69a82800b71 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:52:28 +0200 Subject: [PATCH] Prevent `bcrypt` from raising a `ValueError` and log (#19078) --- changelog.d/19078.bugfix | 1 + synapse/_scripts/hash_password.py | 12 +++++++++++- synapse/handlers/auth.py | 16 +++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 changelog.d/19078.bugfix diff --git a/changelog.d/19078.bugfix b/changelog.d/19078.bugfix new file mode 100644 index 000000000..0046afccc --- /dev/null +++ b/changelog.d/19078.bugfix @@ -0,0 +1 @@ +Fix a bug introduced in 1.140.0 where an internal server error could be raised when hashing user passwords that are too long. \ No newline at end of file diff --git a/synapse/_scripts/hash_password.py b/synapse/_scripts/hash_password.py index 2b7d3585c..6a87303fc 100755 --- a/synapse/_scripts/hash_password.py +++ b/synapse/_scripts/hash_password.py @@ -73,8 +73,18 @@ def main() -> None: pw = unicodedata.normalize("NFKC", password) + bytes_to_hash = pw.encode("utf8") + password_pepper.encode("utf8") + if len(bytes_to_hash) > 72: + # bcrypt only looks at the first 72 bytes + print( + f"Password is too long ({len(bytes_to_hash)} bytes); truncating to 72 bytes for bcrypt. " + "This is expected behaviour and will not affect a user's ability to log in. 72 bytes is " + "sufficient entropy for a password." + ) + bytes_to_hash = bytes_to_hash[:72] + hashed = bcrypt.hashpw( - pw.encode("utf8") + password_pepper.encode("utf8"), + bytes_to_hash, bcrypt.gensalt(bcrypt_rounds), ).decode("ascii") diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index 2d1990cce..f4583e33c 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -1683,8 +1683,22 @@ class AuthHandler: # Normalise the Unicode in the password pw = unicodedata.normalize("NFKC", password) + bytes_to_hash = pw.encode( + "utf8" + ) + self.hs.config.auth.password_pepper.encode("utf8") + if len(bytes_to_hash) > 72: + # bcrypt only looks at the first 72 bytes. + # + # Note: we explicitly DO NOT log the length of the user's password here. + logger.debug( + "Password is too long; truncating to 72 bytes for bcrypt. " + "This is expected behaviour and will not affect a user's ability to log in. 72 bytes is " + "sufficient entropy for a password." + ) + bytes_to_hash = bytes_to_hash[:72] + return bcrypt.hashpw( - pw.encode("utf8") + self.hs.config.auth.password_pepper.encode("utf8"), + bytes_to_hash, bcrypt.gensalt(self.bcrypt_rounds), ).decode("ascii")