From db9a61c30f1066f87047eb60e435917c6478311f Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:16:02 +0100 Subject: [PATCH] Fix `bcrypt` errors preventing users from being able to log in (#19101) --- changelog.d/19101.bugfix | 1 + docs/usage/configuration/config_documentation.md | 2 +- schema/synapse-config.schema.yaml | 5 +++-- synapse/_scripts/hash_password.py | 2 +- synapse/handlers/auth.py | 15 +++++++++++++-- 5 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 changelog.d/19101.bugfix diff --git a/changelog.d/19101.bugfix b/changelog.d/19101.bugfix new file mode 100644 index 000000000..9f481b462 --- /dev/null +++ b/changelog.d/19101.bugfix @@ -0,0 +1 @@ +Fix users being unable to log in if their password, or the server's configured pepper, was too long. \ No newline at end of file diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index fec8d468a..7509e4d71 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3815,7 +3815,7 @@ This setting has the following sub-options: * `localdb_enabled` (boolean): Set to false to disable authentication against the local password database. This is ignored if `enabled` is false, and is only useful if you have other `password_providers`. Defaults to `true`. -* `pepper` (string|null): Set the value here to a secret random string for extra security. DO NOT CHANGE THIS AFTER INITIAL SETUP! Defaults to `null`. +* `pepper` (string|null): A secret random string that will be appended to user's passwords before they are hashed. This improves the security of short passwords. DO NOT CHANGE THIS AFTER INITIAL SETUP! Defaults to `null`. * `policy` (object): Define and enforce a password policy, such as minimum lengths for passwords, etc. This is an implementation of MSC2000. diff --git a/schema/synapse-config.schema.yaml b/schema/synapse-config.schema.yaml index 419a0ab91..75a9a0aac 100644 --- a/schema/synapse-config.schema.yaml +++ b/schema/synapse-config.schema.yaml @@ -4695,8 +4695,9 @@ properties: pepper: type: ["string", "null"] description: >- - Set the value here to a secret random string for extra security. DO - NOT CHANGE THIS AFTER INITIAL SETUP! + A secret random string that will be appended to user's passwords + before they are hashed. This improves the security of short passwords. + DO NOT CHANGE THIS AFTER INITIAL SETUP! default: null policy: type: object diff --git a/synapse/_scripts/hash_password.py b/synapse/_scripts/hash_password.py index 6a87303fc..ae475b849 100755 --- a/synapse/_scripts/hash_password.py +++ b/synapse/_scripts/hash_password.py @@ -77,7 +77,7 @@ def main() -> None: 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. " + f"Password + pepper 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." ) diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py index f4583e33c..564d5f723 100644 --- a/synapse/handlers/auth.py +++ b/synapse/handlers/auth.py @@ -1691,7 +1691,7 @@ class AuthHandler: # # 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. " + "Password + pepper 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." ) @@ -1720,9 +1720,20 @@ class AuthHandler: def _do_validate_hash(checked_hash: bytes) -> bool: # Normalise the Unicode in the password pw = unicodedata.normalize("NFKC", password) + password_pepper = self.hs.config.auth.password_pepper + + bytes_to_hash = pw.encode("utf8") + password_pepper.encode("utf8") + if len(bytes_to_hash) > 72: + # bcrypt only looks at the first 72 bytes + logger.debug( + "Password + pepper 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.checkpw( - pw.encode("utf8") + self.hs.config.auth.password_pepper.encode("utf8"), + bytes_to_hash, checked_hash, )