Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/ecdsa/curves.py: 42%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import division
3from six import PY2
4from . import der, ecdsa, ellipticcurve, eddsa
5from .util import orderlen, number_to_string, string_to_number
6from ._compat import normalise_bytes, bit_length
9# orderlen was defined in this module previously, so keep it in __all__,
10# will need to mark it as deprecated later
11__all__ = [
12 "UnknownCurveError",
13 "orderlen",
14 "Curve",
15 "SECP112r1",
16 "SECP112r2",
17 "SECP128r1",
18 "SECP160r1",
19 "NIST192p",
20 "NIST224p",
21 "NIST256p",
22 "NIST384p",
23 "NIST521p",
24 "curves",
25 "find_curve",
26 "curve_by_name",
27 "SECP256k1",
28 "BRAINPOOLP160r1",
29 "BRAINPOOLP160t1",
30 "BRAINPOOLP192r1",
31 "BRAINPOOLP192t1",
32 "BRAINPOOLP224r1",
33 "BRAINPOOLP224t1",
34 "BRAINPOOLP256r1",
35 "BRAINPOOLP256t1",
36 "BRAINPOOLP320r1",
37 "BRAINPOOLP320t1",
38 "BRAINPOOLP384r1",
39 "BRAINPOOLP384t1",
40 "BRAINPOOLP512r1",
41 "BRAINPOOLP512t1",
42 "PRIME_FIELD_OID",
43 "CHARACTERISTIC_TWO_FIELD_OID",
44 "Ed25519",
45 "Ed448",
46]
49PRIME_FIELD_OID = (1, 2, 840, 10045, 1, 1)
50CHARACTERISTIC_TWO_FIELD_OID = (1, 2, 840, 10045, 1, 2)
53class UnknownCurveError(Exception):
54 pass
57class Curve:
58 def __init__(self, name, curve, generator, oid, openssl_name=None):
59 self.name = name
60 self.openssl_name = openssl_name # maybe None
61 self.curve = curve
62 self.generator = generator
63 self.order = generator.order()
64 if isinstance(curve, ellipticcurve.CurveEdTw):
65 # EdDSA keys are special in that both private and public
66 # are the same size (as it's defined only with compressed points)
68 # +1 for the sign bit and then round up
69 self.baselen = (bit_length(curve.p()) + 1 + 7) // 8
70 self.verifying_key_length = self.baselen
71 else:
72 self.baselen = orderlen(self.order)
73 self.verifying_key_length = 2 * orderlen(curve.p())
74 self.signature_length = 2 * self.baselen
75 self.oid = oid
76 if oid:
77 self.encoded_oid = der.encode_oid(*oid)
79 def __eq__(self, other):
80 if isinstance(other, Curve):
81 return (
82 self.curve == other.curve and self.generator == other.generator
83 )
84 return NotImplemented
86 def __ne__(self, other):
87 return not self == other
89 def __repr__(self):
90 return self.name
92 def to_der(self, encoding=None, point_encoding="uncompressed"):
93 """Serialise the curve parameters to binary string.
95 :param str encoding: the format to save the curve parameters in.
96 Default is ``named_curve``, with fallback being the ``explicit``
97 if the OID is not set for the curve.
98 :param str point_encoding: the point encoding of the generator when
99 explicit curve encoding is used. Ignored for ``named_curve``
100 format.
102 :return: DER encoded ECParameters structure
103 :rtype: bytes
104 """
105 if encoding is None:
106 if self.oid:
107 encoding = "named_curve"
108 else:
109 encoding = "explicit"
111 if encoding not in ("named_curve", "explicit"):
112 raise ValueError(
113 "Only 'named_curve' and 'explicit' encodings supported"
114 )
116 if encoding == "named_curve":
117 if not self.oid:
118 raise UnknownCurveError(
119 "Can't encode curve using named_curve encoding without "
120 "associated curve OID"
121 )
122 return der.encode_oid(*self.oid)
123 elif isinstance(self.curve, ellipticcurve.CurveEdTw):
124 assert encoding == "explicit"
125 raise UnknownCurveError(
126 "Twisted Edwards curves don't support explicit encoding"
127 )
129 # encode the ECParameters sequence
130 curve_p = self.curve.p()
131 version = der.encode_integer(1)
132 field_id = der.encode_sequence(
133 der.encode_oid(*PRIME_FIELD_OID), der.encode_integer(curve_p)
134 )
135 curve = der.encode_sequence(
136 der.encode_octet_string(
137 number_to_string(self.curve.a() % curve_p, curve_p)
138 ),
139 der.encode_octet_string(
140 number_to_string(self.curve.b() % curve_p, curve_p)
141 ),
142 )
143 base = der.encode_octet_string(self.generator.to_bytes(point_encoding))
144 order = der.encode_integer(self.generator.order())
145 seq_elements = [version, field_id, curve, base, order]
146 if self.curve.cofactor():
147 cofactor = der.encode_integer(self.curve.cofactor())
148 seq_elements.append(cofactor)
150 return der.encode_sequence(*seq_elements)
152 def to_pem(self, encoding=None, point_encoding="uncompressed"):
153 """
154 Serialise the curve parameters to the :term:`PEM` format.
156 :param str encoding: the format to save the curve parameters in.
157 Default is ``named_curve``, with fallback being the ``explicit``
158 if the OID is not set for the curve.
159 :param str point_encoding: the point encoding of the generator when
160 explicit curve encoding is used. Ignored for ``named_curve``
161 format.
163 :return: PEM encoded ECParameters structure
164 :rtype: str
165 """
166 return der.topem(
167 self.to_der(encoding, point_encoding), "EC PARAMETERS"
168 )
170 @staticmethod
171 def from_der(data, valid_encodings=None):
172 """Decode the curve parameters from DER file.
174 :param data: the binary string to decode the parameters from
175 :type data: :term:`bytes-like object`
176 :param valid_encodings: set of names of allowed encodings, by default
177 all (set by passing ``None``), supported ones are ``named_curve``
178 and ``explicit``
179 :type valid_encodings: :term:`set-like object`
180 """
181 if not valid_encodings:
182 valid_encodings = set(("named_curve", "explicit"))
183 if not all(i in ["named_curve", "explicit"] for i in valid_encodings):
184 raise ValueError(
185 "Only named_curve and explicit encodings supported"
186 )
187 data = normalise_bytes(data)
188 if not der.is_sequence(data):
189 if "named_curve" not in valid_encodings:
190 raise der.UnexpectedDER(
191 "named_curve curve parameters not allowed"
192 )
193 oid, empty = der.remove_object(data)
194 if empty:
195 raise der.UnexpectedDER("Unexpected data after OID")
196 return find_curve(oid)
198 if "explicit" not in valid_encodings:
199 raise der.UnexpectedDER("explicit curve parameters not allowed")
201 seq, empty = der.remove_sequence(data)
202 if empty:
203 raise der.UnexpectedDER(
204 "Unexpected data after ECParameters structure"
205 )
206 # decode the ECParameters sequence
207 version, rest = der.remove_integer(seq)
208 if version != 1:
209 raise der.UnexpectedDER("Unknown parameter encoding format")
210 field_id, rest = der.remove_sequence(rest)
211 curve, rest = der.remove_sequence(rest)
212 base_bytes, rest = der.remove_octet_string(rest)
213 order, rest = der.remove_integer(rest)
214 cofactor = None
215 if rest:
216 # the ASN.1 specification of ECParameters allows for future
217 # extensions of the sequence, so ignore the remaining bytes
218 cofactor, _ = der.remove_integer(rest)
220 # decode the ECParameters.fieldID sequence
221 field_type, rest = der.remove_object(field_id)
222 if field_type == CHARACTERISTIC_TWO_FIELD_OID:
223 raise UnknownCurveError("Characteristic 2 curves unsupported")
224 if field_type != PRIME_FIELD_OID:
225 raise UnknownCurveError(
226 "Unknown field type: {0}".format(field_type)
227 )
228 prime, empty = der.remove_integer(rest)
229 if empty:
230 raise der.UnexpectedDER(
231 "Unexpected data after ECParameters.fieldID.Prime-p element"
232 )
234 # decode the ECParameters.curve sequence
235 curve_a_bytes, rest = der.remove_octet_string(curve)
236 curve_b_bytes, rest = der.remove_octet_string(rest)
237 # seed can be defined here, but we don't parse it, so ignore `rest`
239 curve_a = string_to_number(curve_a_bytes)
240 curve_b = string_to_number(curve_b_bytes)
242 curve_fp = ellipticcurve.CurveFp(prime, curve_a, curve_b, cofactor)
244 # decode the ECParameters.base point
246 base = ellipticcurve.PointJacobi.from_bytes(
247 curve_fp,
248 base_bytes,
249 valid_encodings=("uncompressed", "compressed", "hybrid"),
250 order=order,
251 generator=True,
252 )
253 tmp_curve = Curve("unknown", curve_fp, base, None)
255 # if the curve matches one of the well-known ones, use the well-known
256 # one in preference, as it will have the OID and name associated
257 for i in curves:
258 if tmp_curve == i:
259 return i
260 return tmp_curve
262 @classmethod
263 def from_pem(cls, string, valid_encodings=None):
264 """Decode the curve parameters from PEM file.
266 :param str string: the text string to decode the parameters from
267 :param valid_encodings: set of names of allowed encodings, by default
268 all (set by passing ``None``), supported ones are ``named_curve``
269 and ``explicit``
270 :type valid_encodings: :term:`set-like object`
271 """
272 if not PY2 and isinstance(string, str): # pragma: no branch
273 string = string.encode()
275 ec_param_index = string.find(b"-----BEGIN EC PARAMETERS-----")
276 if ec_param_index == -1:
277 raise der.UnexpectedDER("EC PARAMETERS PEM header not found")
279 return cls.from_der(
280 der.unpem(string[ec_param_index:]), valid_encodings
281 )
284# the SEC curves
285SECP112r1 = Curve(
286 "SECP112r1",
287 ecdsa.curve_112r1,
288 ecdsa.generator_112r1,
289 (1, 3, 132, 0, 6),
290 "secp112r1",
291)
294SECP112r2 = Curve(
295 "SECP112r2",
296 ecdsa.curve_112r2,
297 ecdsa.generator_112r2,
298 (1, 3, 132, 0, 7),
299 "secp112r2",
300)
303SECP128r1 = Curve(
304 "SECP128r1",
305 ecdsa.curve_128r1,
306 ecdsa.generator_128r1,
307 (1, 3, 132, 0, 28),
308 "secp128r1",
309)
312SECP160r1 = Curve(
313 "SECP160r1",
314 ecdsa.curve_160r1,
315 ecdsa.generator_160r1,
316 (1, 3, 132, 0, 8),
317 "secp160r1",
318)
321# the NIST curves
322NIST192p = Curve(
323 "NIST192p",
324 ecdsa.curve_192,
325 ecdsa.generator_192,
326 (1, 2, 840, 10045, 3, 1, 1),
327 "prime192v1",
328)
331NIST224p = Curve(
332 "NIST224p",
333 ecdsa.curve_224,
334 ecdsa.generator_224,
335 (1, 3, 132, 0, 33),
336 "secp224r1",
337)
340NIST256p = Curve(
341 "NIST256p",
342 ecdsa.curve_256,
343 ecdsa.generator_256,
344 (1, 2, 840, 10045, 3, 1, 7),
345 "prime256v1",
346)
349NIST384p = Curve(
350 "NIST384p",
351 ecdsa.curve_384,
352 ecdsa.generator_384,
353 (1, 3, 132, 0, 34),
354 "secp384r1",
355)
358NIST521p = Curve(
359 "NIST521p",
360 ecdsa.curve_521,
361 ecdsa.generator_521,
362 (1, 3, 132, 0, 35),
363 "secp521r1",
364)
367SECP256k1 = Curve(
368 "SECP256k1",
369 ecdsa.curve_secp256k1,
370 ecdsa.generator_secp256k1,
371 (1, 3, 132, 0, 10),
372 "secp256k1",
373)
376BRAINPOOLP160r1 = Curve(
377 "BRAINPOOLP160r1",
378 ecdsa.curve_brainpoolp160r1,
379 ecdsa.generator_brainpoolp160r1,
380 (1, 3, 36, 3, 3, 2, 8, 1, 1, 1),
381 "brainpoolP160r1",
382)
385BRAINPOOLP160t1 = Curve(
386 "BRAINPOOLP160t1",
387 ecdsa.curve_brainpoolp160t1,
388 ecdsa.generator_brainpoolp160t1,
389 (1, 3, 36, 3, 3, 2, 8, 1, 1, 2),
390 "brainpoolP160t1",
391)
394BRAINPOOLP192r1 = Curve(
395 "BRAINPOOLP192r1",
396 ecdsa.curve_brainpoolp192r1,
397 ecdsa.generator_brainpoolp192r1,
398 (1, 3, 36, 3, 3, 2, 8, 1, 1, 3),
399 "brainpoolP192r1",
400)
403BRAINPOOLP192t1 = Curve(
404 "BRAINPOOLP192t1",
405 ecdsa.curve_brainpoolp192t1,
406 ecdsa.generator_brainpoolp192t1,
407 (1, 3, 36, 3, 3, 2, 8, 1, 1, 4),
408 "brainpoolP192t1",
409)
412BRAINPOOLP224r1 = Curve(
413 "BRAINPOOLP224r1",
414 ecdsa.curve_brainpoolp224r1,
415 ecdsa.generator_brainpoolp224r1,
416 (1, 3, 36, 3, 3, 2, 8, 1, 1, 5),
417 "brainpoolP224r1",
418)
421BRAINPOOLP224t1 = Curve(
422 "BRAINPOOLP224t1",
423 ecdsa.curve_brainpoolp224t1,
424 ecdsa.generator_brainpoolp224t1,
425 (1, 3, 36, 3, 3, 2, 8, 1, 1, 6),
426 "brainpoolP224t1",
427)
430BRAINPOOLP256r1 = Curve(
431 "BRAINPOOLP256r1",
432 ecdsa.curve_brainpoolp256r1,
433 ecdsa.generator_brainpoolp256r1,
434 (1, 3, 36, 3, 3, 2, 8, 1, 1, 7),
435 "brainpoolP256r1",
436)
439BRAINPOOLP256t1 = Curve(
440 "BRAINPOOLP256t1",
441 ecdsa.curve_brainpoolp256t1,
442 ecdsa.generator_brainpoolp256t1,
443 (1, 3, 36, 3, 3, 2, 8, 1, 1, 8),
444 "brainpoolP256t1",
445)
448BRAINPOOLP320r1 = Curve(
449 "BRAINPOOLP320r1",
450 ecdsa.curve_brainpoolp320r1,
451 ecdsa.generator_brainpoolp320r1,
452 (1, 3, 36, 3, 3, 2, 8, 1, 1, 9),
453 "brainpoolP320r1",
454)
457BRAINPOOLP320t1 = Curve(
458 "BRAINPOOLP320t1",
459 ecdsa.curve_brainpoolp320t1,
460 ecdsa.generator_brainpoolp320t1,
461 (1, 3, 36, 3, 3, 2, 8, 1, 1, 10),
462 "brainpoolP320t1",
463)
466BRAINPOOLP384r1 = Curve(
467 "BRAINPOOLP384r1",
468 ecdsa.curve_brainpoolp384r1,
469 ecdsa.generator_brainpoolp384r1,
470 (1, 3, 36, 3, 3, 2, 8, 1, 1, 11),
471 "brainpoolP384r1",
472)
475BRAINPOOLP384t1 = Curve(
476 "BRAINPOOLP384t1",
477 ecdsa.curve_brainpoolp384t1,
478 ecdsa.generator_brainpoolp384t1,
479 (1, 3, 36, 3, 3, 2, 8, 1, 1, 12),
480 "brainpoolP384t1",
481)
484BRAINPOOLP512r1 = Curve(
485 "BRAINPOOLP512r1",
486 ecdsa.curve_brainpoolp512r1,
487 ecdsa.generator_brainpoolp512r1,
488 (1, 3, 36, 3, 3, 2, 8, 1, 1, 13),
489 "brainpoolP512r1",
490)
493BRAINPOOLP512t1 = Curve(
494 "BRAINPOOLP512t1",
495 ecdsa.curve_brainpoolp512t1,
496 ecdsa.generator_brainpoolp512t1,
497 (1, 3, 36, 3, 3, 2, 8, 1, 1, 14),
498 "brainpoolP512t1",
499)
502Ed25519 = Curve(
503 "Ed25519",
504 eddsa.curve_ed25519,
505 eddsa.generator_ed25519,
506 (1, 3, 101, 112),
507)
510Ed448 = Curve(
511 "Ed448",
512 eddsa.curve_ed448,
513 eddsa.generator_ed448,
514 (1, 3, 101, 113),
515)
518# no order in particular, but keep previously added curves first
519curves = [
520 NIST192p,
521 NIST224p,
522 NIST256p,
523 NIST384p,
524 NIST521p,
525 SECP256k1,
526 BRAINPOOLP160r1,
527 BRAINPOOLP192r1,
528 BRAINPOOLP224r1,
529 BRAINPOOLP256r1,
530 BRAINPOOLP320r1,
531 BRAINPOOLP384r1,
532 BRAINPOOLP512r1,
533 SECP112r1,
534 SECP112r2,
535 SECP128r1,
536 SECP160r1,
537 Ed25519,
538 Ed448,
539 BRAINPOOLP160t1,
540 BRAINPOOLP192t1,
541 BRAINPOOLP224t1,
542 BRAINPOOLP256t1,
543 BRAINPOOLP320t1,
544 BRAINPOOLP384t1,
545 BRAINPOOLP512t1,
546]
549def find_curve(oid_curve):
550 """Select a curve based on its OID
552 :param tuple[int,...] oid_curve: ASN.1 Object Identifier of the
553 curve to return, like ``(1, 2, 840, 10045, 3, 1, 7)`` for ``NIST256p``.
555 :raises UnknownCurveError: When the oid doesn't match any of the supported
556 curves
558 :rtype: ~ecdsa.curves.Curve
559 """
560 for c in curves:
561 if c.oid == oid_curve:
562 return c
563 raise UnknownCurveError(
564 "I don't know about the curve with oid %s."
565 "I only know about these: %s" % (oid_curve, [c.name for c in curves])
566 )
569def curve_by_name(name):
570 """Select a curve based on its name.
572 Returns a :py:class:`~ecdsa.curves.Curve` object with a ``name`` name.
573 Note that ``name`` is case-sensitve.
575 :param str name: Name of the curve to return, like ``NIST256p`` or
576 ``prime256v1``
578 :raises UnknownCurveError: When the name doesn't match any of the supported
579 curves
581 :rtype: ~ecdsa.curves.Curve
582 """
583 for c in curves:
584 if name == c.name or (c.openssl_name and name == c.openssl_name):
585 return c
586 raise UnknownCurveError(
587 "Curve with name {0!r} unknown, only curves supported: {1}".format(
588 name, [c.name for c in curves]
589 )
590 )