From 09bef94ffe2b2bcf781603289ba0884fa9b861a1 Mon Sep 17 00:00:00 2001 From: Goffi Date: Thu, 9 Apr 2026 21:42:16 +0200 Subject: [PATCH] plugin XEP-0373, tests (unit/XEP-0373): Make `rpad` size >= 50: XEP-0420 bounds starts at 0 but 0-length rpad defeats its purpose (the XEP actually says "TODO: sane boundaries?"). Furthermore, some tests where failing randomly due to 0-lenght rpad sometimes happening. This patch makes rpad minimum size at 50. --- libervia/backend/plugins/plugin_xep_0373/__init__.py | 7 +++++-- tests/unit/test_plugin_xep_0373.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/libervia/backend/plugins/plugin_xep_0373/__init__.py b/libervia/backend/plugins/plugin_xep_0373/__init__.py index 06f1a0eb..ba220aeb 100644 --- a/libervia/backend/plugins/plugin_xep_0373/__init__.py +++ b/libervia/backend/plugins/plugin_xep_0373/__init__.py @@ -602,8 +602,11 @@ class XEP_0373: if include_rpad: # XEP-0373 doesn't specify bounds for the length of the random padding. This - # uses the bounds specified in XEP-0420 for the closely related rpad affix. - rpad_length = secrets.randbelow(201) + # uses the bounds specified in XEP-0420 for the closely related rpad affix. We + # use a minimum of 50 characters to ensure meaningful protection against + # length-based side channel attacks. XEP-0420 specifies 0-200 characters, but + # 0-length padding defeats the security purpose of rpad. + rpad_length = secrets.randbelow(151) + 50 # Range [50, 200] rpad_content = "".join( secrets.choice(string.digits + string.ascii_letters + string.punctuation) for __ in range(rpad_length) diff --git a/tests/unit/test_plugin_xep_0373.py b/tests/unit/test_plugin_xep_0373.py index 6cb291b8..d0f4dc9b 100644 --- a/tests/unit/test_plugin_xep_0373.py +++ b/tests/unit/test_plugin_xep_0373.py @@ -32,7 +32,8 @@ def test_signcrypt_element() -> None: signcrypt_elt.children.remove(rpad_elt) signcrypt_elt.children.remove(time_elt) - assert rpad + # Our implementation uses a minimum of 50 characters for security + assert len(rpad) >= 50 assert (datetime.now(timezone.utc) - timestamp) < timedelta(seconds=10) assert signcrypt_elt.toXml() == ( "" @@ -63,7 +64,8 @@ def test_sign_element_with_rpad() -> None: sign_elt.children.remove(rpad_elt) sign_elt.children.remove(time_elt) - assert rpad + # Our implementation uses a minimum of 50 characters for security + assert len(rpad) >= 50 assert (datetime.now(timezone.utc) - timestamp) < timedelta(seconds=10) assert sign_elt.toXml() == ( "" @@ -113,7 +115,8 @@ def test_crypt_element_with_recipients() -> None: crypt_elt.children.remove(rpad_elt) crypt_elt.children.remove(time_elt) - assert rpad + # Our implementation uses a minimum of 50 characters for security + assert len(rpad) >= 50 assert (datetime.now(timezone.utc) - timestamp) < timedelta(seconds=10) assert crypt_elt.toXml() == ( "" @@ -139,7 +142,8 @@ def test_crypt_element_without_recipients() -> None: crypt_elt.children.remove(rpad_elt) crypt_elt.children.remove(time_elt) - assert rpad + # Our implementation uses a minimum of 50 characters for security + assert len(rpad) >= 50 assert (datetime.now(timezone.utc) - timestamp) < timedelta(seconds=10) assert crypt_elt.toXml() == ( ""