Skip to content

Commit

Permalink
Check weak points on Curve448
Browse files Browse the repository at this point in the history
  • Loading branch information
Legrandin committed Sep 8, 2024
1 parent 767ac2e commit 8f58ac4
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 40 deletions.
40 changes: 4 additions & 36 deletions lib/Crypto/PublicKey/ECC.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,11 @@ def generate(**kwargs):
elif _curves[curve_name].id == _CurveID.CURVE25519:
seed = randfunc(32)
new_key = EccKey(curve=curve_name, seed=seed)
_validate_x25519_public_key(new_key)
_curves[curve_name].validate(new_key.pointQ)
elif _curves[curve_name].id == _CurveID.CURVE448:
seed = randfunc(56)
new_key = EccKey(curve=curve_name, seed=seed)
_validate_x448_public_key(new_key)
_curves[curve_name].validate(new_key.pointQ)
else:
d = Integer.random_range(min_inclusive=1,
max_exclusive=curve.order,
Expand Down Expand Up @@ -667,14 +667,14 @@ def construct(**kwargs):
if point_x is not None:
kwargs["point"] = EccXPoint(point_x, curve_name)
new_key = EccKey(**kwargs)
_validate_x25519_public_key(new_key)
curve.validate(new_key.pointQ)

elif curve.id == _CurveID.CURVE448:

if point_x is not None:
kwargs["point"] = EccXPoint(point_x, curve_name)
new_key = EccKey(**kwargs)
_validate_x448_public_key(new_key)
curve.validate(new_key.pointQ)

else:

Expand Down Expand Up @@ -1152,38 +1152,6 @@ def _import_curve448_public_key(encoded):
return point_x


def _validate_x25519_public_key(new_key):

p = _curves['curve25519'].p
p2 = p * 2
x1 = 325606250916557431795983626356110631294008115727848805560023387167927233504
x2 = 39382357235489614581723060781553021112529911719440698176882885853963445705823

# http://cr.yp.to/ecdh.html#validate
deny_list = (
0,
1,
x1,
x2,
p - 1,
p,
p + 1,
p + x1,
p + x2,
p2 - 1,
p2,
p2 + 1,
)

if new_key.pointQ.x in deny_list:
raise ValueError("Invalid Curve25519 public key")


def _validate_x448_public_key(new_key):
#: TODO
pass


def _import_ed448_public_key(encoded):
"""Import an Ed448 ECC public key, encoded as raw bytes as described
in RFC8032_.
Expand Down
4 changes: 3 additions & 1 deletion lib/Crypto/PublicKey/_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
# - canonical the canonical name of the curve
# - openssh the ASCII string used in OpenSSH id files for public keys on this curve
# - rawlib the reference to the dynamic libary with the low-level functions
# - validate a function that raises an exception if the the input point is invalid

class _Curve(object):

def __init__(self, p, b, order, Gx, Gy, G, modulus_bits, oid, context,
canonical, openssh, rawlib):
canonical, openssh, rawlib, validate=None):
self.p = p
self.b = b
self.order = order
Expand All @@ -33,3 +34,4 @@ def __init__(self, p, b, order, Gx, Gy, G, modulus_bits, oid, context,
self.canonical = canonical
self.openssh = openssh
self.rawlib = rawlib
self.validate = validate
57 changes: 55 additions & 2 deletions lib/Crypto/PublicKey/_montgomery.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,36 @@ class EcLib(object):
scalar = _curve25519_lib.curve25519_scalar
cmp = _curve25519_lib.curve25519_cmp

def _validate_x25519_point(point):

p2 = p * 2
x1 = 325606250916557431795983626356110631294008115727848805560023387167927233504
x2 = 39382357235489614581723060781553021112529911719440698176882885853963445705823

# http://cr.yp.to/ecdh.html#validate
deny_list = (
0,
1,
x1,
x2,
p - 1,
p,
p + 1,
p + x1,
p + x2,
p2 - 1,
p2,
p2 + 1,
)

try:
valid = point.x not in deny_list
except ValueError:
valid = False

if not valid:
raise ValueError("Invalid Curve25519 public key")

curve25519 = _Curve(Integer(p),
None,
Integer(order),
Expand All @@ -44,7 +74,10 @@ class EcLib(object):
None,
"Curve25519",
None,
EcLib)
EcLib,
_validate_x25519_point,
)

return curve25519


Expand Down Expand Up @@ -84,6 +117,23 @@ class EcLib(object):
if result:
raise ImportError("Error %d initializing Curve448 context" % result)

def _validate_x448_point(point):
deny_list = (
0,
1,
p - 1,
p,
p + 1,
)

try:
valid = point.x not in deny_list
except ValueError:
valid = False

if not valid:
raise ValueError("Invalid Curve448 public key")

curve448 = _Curve(Integer(p),
None,
Integer(order),
Expand All @@ -95,5 +145,8 @@ class EcLib(object):
SmartPointer(curve448_context.get(), EcLib.free_context),
"Curve448",
None,
EcLib)
EcLib,
_validate_x448_point,
)

return curve448
12 changes: 11 additions & 1 deletion lib/Crypto/SelfTest/PublicKey/test_ECC_Curve448.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,17 @@ def test_negative_construct(self):
seed=b'H'*55)

# Verify you cannot construct weak keys (small-order points)
# TODO
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=0)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=1)
p = 2**448 - 2**224 - 1
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p-1)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p)
self.assertRaises(ValueError, ECC.construct, curve="Curve448",
point_x=p+1)


def get_tests(config={}):
Expand Down

0 comments on commit 8f58ac4

Please sign in to comment.