From 98a67478de0c8fecba5b36e936f4a1ae1f4b69cc Mon Sep 17 00:00:00 2001 From: deadcafe Date: Mon, 5 Oct 2026 04:05:02 +0530 Subject: [PATCH] Reject public keys that are not on the curve in the builtin ECDH The builtin crypto backend computed a shared secret for any (x, y) pair, including points that are not on P-256: (1, 1) produced a secret and (0, 0) produced an all-zero one. The cryptography backend already rejects such keys with a ValueError. Check the curve equation before the scalar multiplication and raise InvalidPacketError, so that SMP answers with Pairing Failed as it does with the cryptography backend. --- bumble/crypto/builtin.py | 3 +++ tests/crypto/crypto_test.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/bumble/crypto/builtin.py b/bumble/crypto/builtin.py index 03d391e85..12cdd7752 100644 --- a/bumble/crypto/builtin.py +++ b/bumble/crypto/builtin.py @@ -572,6 +572,9 @@ def generate_public_key(self, private_key: int) -> _Point: def ecdh_shared_secret(self, private_key: int, other_public_key: _Point) -> bytes: """Computes the shared secret using ECDH.""" + x, y = other_public_key.x, other_public_key.y + if (y * y - (x * x * x + self.a * x + self.b)) % self.p != 0: + raise core.InvalidPacketError("Public key is not a point on the curve") other_public_key_jacobian = _JacobianPoint.from_affine(other_public_key) shared_point_jacobian = other_public_key_jacobian * private_key shared_point_affine = shared_point_jacobian.to_affine() diff --git a/tests/crypto/crypto_test.py b/tests/crypto/crypto_test.py index 1287ddb64..f6769b917 100644 --- a/tests/crypto/crypto_test.py +++ b/tests/crypto/crypto_test.py @@ -83,6 +83,14 @@ def test_ecc(crypto_backend): assert shared_key == bytes.fromhex(dhkey) +# ----------------------------------------------------------------------------- +@pytest.mark.parametrize("x, y", [(0, 0), (1, 1)]) +def test_ecc_dh_point_not_on_curve(crypto_backend, x, y): + key = EccKey.generate() + with pytest.raises(ValueError): + key.dh(x.to_bytes(32, 'big'), y.to_bytes(32, 'big')) + + # ----------------------------------------------------------------------------- def test_c1(crypto_backend): k = bytes(16)