Skip to content

Commit 46bdd1e

Browse files
committed
add secp160r1; fix handling curves with order > p
the secret multiplier is limited by the order of the base point, that also informs the size of elements for the signature (as they are calculated modulo order), but the public point is a point, so its elements are modulo prime from the curve for all curves up till now the size of order and size of the prime was the same so it worked fine, but secp160r1 is different, so it showed the bug so fix this bug and add secp160r1 as the test coverage for it
1 parent 75705c6 commit 46bdd1e

File tree

5 files changed

+57
-11
lines changed

5 files changed

+57
-11
lines changed

src/ecdsa/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
SECP112r1,
2323
SECP112r2,
2424
SECP128r1,
25+
SECP160r1,
2526
)
2627
from .ecdh import (
2728
ECDH,
@@ -78,5 +79,6 @@
7879
SECP112r1,
7980
SECP112r2,
8081
SECP128r1,
82+
SECP160r1,
8183
]
8284
del _hush_pyflakes

src/ecdsa/curves.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"SECP112r1",
1414
"SECP112r2",
1515
"SECP128r1",
16+
"SECP160r1",
1617
"NIST192p",
1718
"NIST224p",
1819
"NIST256p",
@@ -43,7 +44,7 @@ def __init__(self, name, curve, generator, oid, openssl_name=None):
4344
self.generator = generator
4445
self.order = generator.order()
4546
self.baselen = orderlen(self.order)
46-
self.verifying_key_length = 2 * self.baselen
47+
self.verifying_key_length = 2 * orderlen(curve.p())
4748
self.signature_length = 2 * self.baselen
4849
self.oid = oid
4950
self.encoded_oid = der.encode_oid(*oid)
@@ -80,6 +81,15 @@ def __repr__(self):
8081
)
8182

8283

84+
SECP160r1 = Curve(
85+
"SECP160r1",
86+
ecdsa.curve_160r1,
87+
ecdsa.generator_160r1,
88+
(1, 3, 132, 0, 8),
89+
"secp160r1",
90+
)
91+
92+
8393
# the NIST curves
8494
NIST192p = Curve(
8595
"NIST192p",
@@ -216,6 +226,7 @@ def __repr__(self):
216226
SECP112r1,
217227
SECP112r2,
218228
SECP128r1,
229+
SECP160r1,
219230
]
220231

221232

src/ecdsa/ecdsa.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,21 @@ def point_is_valid(generator, x, y):
339339
)
340340

341341

342+
# secp160r1
343+
_p = int(remove_whitespace("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 7FFFFFFF"), 16)
344+
# S = 1053CDE4 2C14D696 E6768756 1517533B F3F83345
345+
# _a = -3
346+
_b = int(remove_whitespace("1C97BEFC 54BD7A8B 65ACF89F 81D4D4AD C565FA45"), 16)
347+
_Gx = int(remove_whitespace("4A96B568 8EF57328 46646989 68C38BB9 13CBFC82"), 16)
348+
_Gy = int(remove_whitespace("23A62855 3168947D 59DCC912 04235137 7AC5FB32"), 16)
349+
_r = int(remove_whitespace("01 00000000 00000000 0001F4C8 F927AED3 CA752257"), 16)
350+
_h = 1
351+
curve_160r1 = ellipticcurve.CurveFp(_p, -3, _b, _h)
352+
generator_160r1 = ellipticcurve.PointJacobi(
353+
curve_160r1, _Gx, _Gy, 1, _r, generator=True
354+
)
355+
356+
342357
# NIST Curve P-192:
343358
_p = 6277101735386680763835789423207666416083908700390324961279
344359
_r = 6277101735386680763835789423176059013767194773182842284081

src/ecdsa/keys.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,11 +272,11 @@ def _from_raw_encoding(string, curve):
272272
order = curve.order
273273
# real assert, from_string() should not call us with different length
274274
assert len(string) == curve.verifying_key_length
275-
xs = string[: curve.baselen]
276-
ys = string[curve.baselen :]
277-
if len(xs) != curve.baselen:
275+
xs = string[: curve.verifying_key_length // 2]
276+
ys = string[curve.verifying_key_length // 2 :]
277+
if len(xs) != curve.verifying_key_length // 2:
278278
raise MalformedPointError("Unexpected length of encoded x")
279-
if len(ys) != curve.baselen:
279+
if len(ys) != curve.verifying_key_length // 2:
280280
raise MalformedPointError("Unexpected length of encoded y")
281281
x = string_to_number(xs)
282282
y = string_to_number(ys)
@@ -371,7 +371,7 @@ def from_string(
371371
raise MalformedPointError(
372372
"Invalid X9.62 encoding of the public point"
373373
)
374-
elif sig_len == curve.baselen + 1:
374+
elif sig_len == curve.verifying_key_length // 2 + 1:
375375
point = cls._from_compressed(string, curve)
376376
else:
377377
raise MalformedPointError(
@@ -572,14 +572,14 @@ def from_public_key_recovery_with_digest(
572572

573573
def _raw_encode(self):
574574
"""Convert the public key to the :term:`raw encoding`."""
575-
order = self.pubkey.order
575+
order = self.curve.curve.p()
576576
x_str = number_to_string(self.pubkey.point.x(), order)
577577
y_str = number_to_string(self.pubkey.point.y(), order)
578578
return x_str + y_str
579579

580580
def _compressed_encode(self):
581581
"""Encode the public point into the compressed form."""
582-
order = self.pubkey.order
582+
order = self.curve.curve.p()
583583
x_str = number_to_string(self.pubkey.point.x(), order)
584584
if self.pubkey.point.y() & 1:
585585
return b("\x03") + x_str

src/ecdsa/test_pyecdsa.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
SECP112r1,
3030
SECP112r2,
3131
SECP128r1,
32+
SECP160r1,
3233
NIST192p,
3334
NIST224p,
3435
NIST256p,
@@ -313,8 +314,13 @@ class FakeGenerator:
313314
def order(self):
314315
return 123456789
315316

317+
class FakeCurveFp:
318+
def p(self):
319+
return int("6525534529039240705020950546962731340"
320+
"4541085228058844382513856749047873406763")
321+
316322
badcurve = Curve(
317-
"unknown", None, FakeGenerator(), (1, 2, 3, 4, 5, 6), None
323+
"unknown", FakeCurveFp(), FakeGenerator(), (1, 2, 3, 4, 5, 6), None
318324
)
319325
badpub.curve = badcurve
320326
badder = badpub.to_der()
@@ -890,7 +896,13 @@ def test_from_openssl_secp112r2(self):
890896
def test_from_openssl_secp128r1(self):
891897
return self.do_test_from_openssl(SECP128r1)
892898

893-
@pytest.mark.slow
899+
@pytest.mark.skipif(
900+
"secp160r1" not in OPENSSL_SUPPORTED_CURVES,
901+
reason="system openssl does not support secp160r1",
902+
)
903+
def test_from_openssl_secp160r1(self):
904+
return self.do_test_from_openssl(SECP160r1)
905+
894906
@pytest.mark.skipif(
895907
"prime192v1" not in OPENSSL_SUPPORTED_CURVES,
896908
reason="system openssl does not support prime192v1",
@@ -1076,7 +1088,13 @@ def test_to_openssl_secp112r2(self):
10761088
def test_to_openssl_secp128r1(self):
10771089
self.do_test_to_openssl(SECP128r1)
10781090

1079-
@pytest.mark.slow
1091+
@pytest.mark.skipif(
1092+
"secp160r1" not in OPENSSL_SUPPORTED_CURVES,
1093+
reason="system openssl does not support secp160r1",
1094+
)
1095+
def test_to_openssl_secp160r1(self):
1096+
self.do_test_to_openssl(SECP160r1)
1097+
10801098
@pytest.mark.skipif(
10811099
"prime192v1" not in OPENSSL_SUPPORTED_CURVES,
10821100
reason="system openssl does not support prime192v1",

0 commit comments

Comments
 (0)