| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- from __future__ import division
- from six import PY2
- from . import der, ecdsa, ellipticcurve, eddsa
- from .util import orderlen, number_to_string, string_to_number
- from ._compat import normalise_bytes, bit_length
- # orderlen was defined in this module previously, so keep it in __all__,
- # will need to mark it as deprecated later
- __all__ = [
- "UnknownCurveError",
- "orderlen",
- "Curve",
- "SECP112r1",
- "SECP112r2",
- "SECP128r1",
- "SECP160r1",
- "NIST192p",
- "NIST224p",
- "NIST256p",
- "NIST384p",
- "NIST521p",
- "curves",
- "find_curve",
- "curve_by_name",
- "SECP256k1",
- "BRAINPOOLP160r1",
- "BRAINPOOLP160t1",
- "BRAINPOOLP192r1",
- "BRAINPOOLP192t1",
- "BRAINPOOLP224r1",
- "BRAINPOOLP224t1",
- "BRAINPOOLP256r1",
- "BRAINPOOLP256t1",
- "BRAINPOOLP320r1",
- "BRAINPOOLP320t1",
- "BRAINPOOLP384r1",
- "BRAINPOOLP384t1",
- "BRAINPOOLP512r1",
- "BRAINPOOLP512t1",
- "PRIME_FIELD_OID",
- "CHARACTERISTIC_TWO_FIELD_OID",
- "Ed25519",
- "Ed448",
- ]
- PRIME_FIELD_OID = (1, 2, 840, 10045, 1, 1)
- CHARACTERISTIC_TWO_FIELD_OID = (1, 2, 840, 10045, 1, 2)
- class UnknownCurveError(Exception):
- pass
- class Curve:
- def __init__(self, name, curve, generator, oid, openssl_name=None):
- self.name = name
- self.openssl_name = openssl_name # maybe None
- self.curve = curve
- self.generator = generator
- self.order = generator.order()
- if isinstance(curve, ellipticcurve.CurveEdTw):
- # EdDSA keys are special in that both private and public
- # are the same size (as it's defined only with compressed points)
- # +1 for the sign bit and then round up
- self.baselen = (bit_length(curve.p()) + 1 + 7) // 8
- self.verifying_key_length = self.baselen
- else:
- self.baselen = orderlen(self.order)
- self.verifying_key_length = 2 * orderlen(curve.p())
- self.signature_length = 2 * self.baselen
- self.oid = oid
- if oid:
- self.encoded_oid = der.encode_oid(*oid)
- def __eq__(self, other):
- if isinstance(other, Curve):
- return (
- self.curve == other.curve and self.generator == other.generator
- )
- return NotImplemented
- def __ne__(self, other):
- return not self == other
- def __repr__(self):
- return self.name
- def to_der(self, encoding=None, point_encoding="uncompressed"):
- """Serialise the curve parameters to binary string.
- :param str encoding: the format to save the curve parameters in.
- Default is ``named_curve``, with fallback being the ``explicit``
- if the OID is not set for the curve.
- :param str point_encoding: the point encoding of the generator when
- explicit curve encoding is used. Ignored for ``named_curve``
- format.
- :return: DER encoded ECParameters structure
- :rtype: bytes
- """
- if encoding is None:
- if self.oid:
- encoding = "named_curve"
- else:
- encoding = "explicit"
- if encoding not in ("named_curve", "explicit"):
- raise ValueError(
- "Only 'named_curve' and 'explicit' encodings supported"
- )
- if encoding == "named_curve":
- if not self.oid:
- raise UnknownCurveError(
- "Can't encode curve using named_curve encoding without "
- "associated curve OID"
- )
- return der.encode_oid(*self.oid)
- elif isinstance(self.curve, ellipticcurve.CurveEdTw):
- assert encoding == "explicit"
- raise UnknownCurveError(
- "Twisted Edwards curves don't support explicit encoding"
- )
- # encode the ECParameters sequence
- curve_p = self.curve.p()
- version = der.encode_integer(1)
- field_id = der.encode_sequence(
- der.encode_oid(*PRIME_FIELD_OID), der.encode_integer(curve_p)
- )
- curve = der.encode_sequence(
- der.encode_octet_string(
- number_to_string(self.curve.a() % curve_p, curve_p)
- ),
- der.encode_octet_string(
- number_to_string(self.curve.b() % curve_p, curve_p)
- ),
- )
- base = der.encode_octet_string(self.generator.to_bytes(point_encoding))
- order = der.encode_integer(self.generator.order())
- seq_elements = [version, field_id, curve, base, order]
- if self.curve.cofactor():
- cofactor = der.encode_integer(self.curve.cofactor())
- seq_elements.append(cofactor)
- return der.encode_sequence(*seq_elements)
- def to_pem(self, encoding=None, point_encoding="uncompressed"):
- """
- Serialise the curve parameters to the :term:`PEM` format.
- :param str encoding: the format to save the curve parameters in.
- Default is ``named_curve``, with fallback being the ``explicit``
- if the OID is not set for the curve.
- :param str point_encoding: the point encoding of the generator when
- explicit curve encoding is used. Ignored for ``named_curve``
- format.
- :return: PEM encoded ECParameters structure
- :rtype: str
- """
- return der.topem(
- self.to_der(encoding, point_encoding), "EC PARAMETERS"
- )
- @staticmethod
- def from_der(data, valid_encodings=None):
- """Decode the curve parameters from DER file.
- :param data: the binary string to decode the parameters from
- :type data: :term:`bytes-like object`
- :param valid_encodings: set of names of allowed encodings, by default
- all (set by passing ``None``), supported ones are ``named_curve``
- and ``explicit``
- :type valid_encodings: :term:`set-like object`
- """
- if not valid_encodings:
- valid_encodings = set(("named_curve", "explicit"))
- if not all(i in ["named_curve", "explicit"] for i in valid_encodings):
- raise ValueError(
- "Only named_curve and explicit encodings supported"
- )
- data = normalise_bytes(data)
- if not der.is_sequence(data):
- if "named_curve" not in valid_encodings:
- raise der.UnexpectedDER(
- "named_curve curve parameters not allowed"
- )
- oid, empty = der.remove_object(data)
- if empty:
- raise der.UnexpectedDER("Unexpected data after OID")
- return find_curve(oid)
- if "explicit" not in valid_encodings:
- raise der.UnexpectedDER("explicit curve parameters not allowed")
- seq, empty = der.remove_sequence(data)
- if empty:
- raise der.UnexpectedDER(
- "Unexpected data after ECParameters structure"
- )
- # decode the ECParameters sequence
- version, rest = der.remove_integer(seq)
- if version != 1:
- raise der.UnexpectedDER("Unknown parameter encoding format")
- field_id, rest = der.remove_sequence(rest)
- curve, rest = der.remove_sequence(rest)
- base_bytes, rest = der.remove_octet_string(rest)
- order, rest = der.remove_integer(rest)
- cofactor = None
- if rest:
- # the ASN.1 specification of ECParameters allows for future
- # extensions of the sequence, so ignore the remaining bytes
- cofactor, _ = der.remove_integer(rest)
- # decode the ECParameters.fieldID sequence
- field_type, rest = der.remove_object(field_id)
- if field_type == CHARACTERISTIC_TWO_FIELD_OID:
- raise UnknownCurveError("Characteristic 2 curves unsupported")
- if field_type != PRIME_FIELD_OID:
- raise UnknownCurveError(
- "Unknown field type: {0}".format(field_type)
- )
- prime, empty = der.remove_integer(rest)
- if empty:
- raise der.UnexpectedDER(
- "Unexpected data after ECParameters.fieldID.Prime-p element"
- )
- # decode the ECParameters.curve sequence
- curve_a_bytes, rest = der.remove_octet_string(curve)
- curve_b_bytes, rest = der.remove_octet_string(rest)
- # seed can be defined here, but we don't parse it, so ignore `rest`
- curve_a = string_to_number(curve_a_bytes)
- curve_b = string_to_number(curve_b_bytes)
- curve_fp = ellipticcurve.CurveFp(prime, curve_a, curve_b, cofactor)
- # decode the ECParameters.base point
- base = ellipticcurve.PointJacobi.from_bytes(
- curve_fp,
- base_bytes,
- valid_encodings=("uncompressed", "compressed", "hybrid"),
- order=order,
- generator=True,
- )
- tmp_curve = Curve("unknown", curve_fp, base, None)
- # if the curve matches one of the well-known ones, use the well-known
- # one in preference, as it will have the OID and name associated
- for i in curves:
- if tmp_curve == i:
- return i
- return tmp_curve
- @classmethod
- def from_pem(cls, string, valid_encodings=None):
- """Decode the curve parameters from PEM file.
- :param str string: the text string to decode the parameters from
- :param valid_encodings: set of names of allowed encodings, by default
- all (set by passing ``None``), supported ones are ``named_curve``
- and ``explicit``
- :type valid_encodings: :term:`set-like object`
- """
- if not PY2 and isinstance(string, str): # pragma: no branch
- string = string.encode()
- ec_param_index = string.find(b"-----BEGIN EC PARAMETERS-----")
- if ec_param_index == -1:
- raise der.UnexpectedDER("EC PARAMETERS PEM header not found")
- return cls.from_der(
- der.unpem(string[ec_param_index:]), valid_encodings
- )
- # the SEC curves
- SECP112r1 = Curve(
- "SECP112r1",
- ecdsa.curve_112r1,
- ecdsa.generator_112r1,
- (1, 3, 132, 0, 6),
- "secp112r1",
- )
- SECP112r2 = Curve(
- "SECP112r2",
- ecdsa.curve_112r2,
- ecdsa.generator_112r2,
- (1, 3, 132, 0, 7),
- "secp112r2",
- )
- SECP128r1 = Curve(
- "SECP128r1",
- ecdsa.curve_128r1,
- ecdsa.generator_128r1,
- (1, 3, 132, 0, 28),
- "secp128r1",
- )
- SECP160r1 = Curve(
- "SECP160r1",
- ecdsa.curve_160r1,
- ecdsa.generator_160r1,
- (1, 3, 132, 0, 8),
- "secp160r1",
- )
- # the NIST curves
- NIST192p = Curve(
- "NIST192p",
- ecdsa.curve_192,
- ecdsa.generator_192,
- (1, 2, 840, 10045, 3, 1, 1),
- "prime192v1",
- )
- NIST224p = Curve(
- "NIST224p",
- ecdsa.curve_224,
- ecdsa.generator_224,
- (1, 3, 132, 0, 33),
- "secp224r1",
- )
- NIST256p = Curve(
- "NIST256p",
- ecdsa.curve_256,
- ecdsa.generator_256,
- (1, 2, 840, 10045, 3, 1, 7),
- "prime256v1",
- )
- NIST384p = Curve(
- "NIST384p",
- ecdsa.curve_384,
- ecdsa.generator_384,
- (1, 3, 132, 0, 34),
- "secp384r1",
- )
- NIST521p = Curve(
- "NIST521p",
- ecdsa.curve_521,
- ecdsa.generator_521,
- (1, 3, 132, 0, 35),
- "secp521r1",
- )
- SECP256k1 = Curve(
- "SECP256k1",
- ecdsa.curve_secp256k1,
- ecdsa.generator_secp256k1,
- (1, 3, 132, 0, 10),
- "secp256k1",
- )
- BRAINPOOLP160r1 = Curve(
- "BRAINPOOLP160r1",
- ecdsa.curve_brainpoolp160r1,
- ecdsa.generator_brainpoolp160r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 1),
- "brainpoolP160r1",
- )
- BRAINPOOLP160t1 = Curve(
- "BRAINPOOLP160t1",
- ecdsa.curve_brainpoolp160t1,
- ecdsa.generator_brainpoolp160t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 2),
- "brainpoolP160t1",
- )
- BRAINPOOLP192r1 = Curve(
- "BRAINPOOLP192r1",
- ecdsa.curve_brainpoolp192r1,
- ecdsa.generator_brainpoolp192r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 3),
- "brainpoolP192r1",
- )
- BRAINPOOLP192t1 = Curve(
- "BRAINPOOLP192t1",
- ecdsa.curve_brainpoolp192t1,
- ecdsa.generator_brainpoolp192t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 4),
- "brainpoolP192t1",
- )
- BRAINPOOLP224r1 = Curve(
- "BRAINPOOLP224r1",
- ecdsa.curve_brainpoolp224r1,
- ecdsa.generator_brainpoolp224r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 5),
- "brainpoolP224r1",
- )
- BRAINPOOLP224t1 = Curve(
- "BRAINPOOLP224t1",
- ecdsa.curve_brainpoolp224t1,
- ecdsa.generator_brainpoolp224t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 6),
- "brainpoolP224t1",
- )
- BRAINPOOLP256r1 = Curve(
- "BRAINPOOLP256r1",
- ecdsa.curve_brainpoolp256r1,
- ecdsa.generator_brainpoolp256r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 7),
- "brainpoolP256r1",
- )
- BRAINPOOLP256t1 = Curve(
- "BRAINPOOLP256t1",
- ecdsa.curve_brainpoolp256t1,
- ecdsa.generator_brainpoolp256t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 8),
- "brainpoolP256t1",
- )
- BRAINPOOLP320r1 = Curve(
- "BRAINPOOLP320r1",
- ecdsa.curve_brainpoolp320r1,
- ecdsa.generator_brainpoolp320r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 9),
- "brainpoolP320r1",
- )
- BRAINPOOLP320t1 = Curve(
- "BRAINPOOLP320t1",
- ecdsa.curve_brainpoolp320t1,
- ecdsa.generator_brainpoolp320t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 10),
- "brainpoolP320t1",
- )
- BRAINPOOLP384r1 = Curve(
- "BRAINPOOLP384r1",
- ecdsa.curve_brainpoolp384r1,
- ecdsa.generator_brainpoolp384r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 11),
- "brainpoolP384r1",
- )
- BRAINPOOLP384t1 = Curve(
- "BRAINPOOLP384t1",
- ecdsa.curve_brainpoolp384t1,
- ecdsa.generator_brainpoolp384t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 12),
- "brainpoolP384t1",
- )
- BRAINPOOLP512r1 = Curve(
- "BRAINPOOLP512r1",
- ecdsa.curve_brainpoolp512r1,
- ecdsa.generator_brainpoolp512r1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 13),
- "brainpoolP512r1",
- )
- BRAINPOOLP512t1 = Curve(
- "BRAINPOOLP512t1",
- ecdsa.curve_brainpoolp512t1,
- ecdsa.generator_brainpoolp512t1,
- (1, 3, 36, 3, 3, 2, 8, 1, 1, 14),
- "brainpoolP512t1",
- )
- Ed25519 = Curve(
- "Ed25519",
- eddsa.curve_ed25519,
- eddsa.generator_ed25519,
- (1, 3, 101, 112),
- )
- Ed448 = Curve(
- "Ed448",
- eddsa.curve_ed448,
- eddsa.generator_ed448,
- (1, 3, 101, 113),
- )
- # no order in particular, but keep previously added curves first
- curves = [
- NIST192p,
- NIST224p,
- NIST256p,
- NIST384p,
- NIST521p,
- SECP256k1,
- BRAINPOOLP160r1,
- BRAINPOOLP192r1,
- BRAINPOOLP224r1,
- BRAINPOOLP256r1,
- BRAINPOOLP320r1,
- BRAINPOOLP384r1,
- BRAINPOOLP512r1,
- SECP112r1,
- SECP112r2,
- SECP128r1,
- SECP160r1,
- Ed25519,
- Ed448,
- BRAINPOOLP160t1,
- BRAINPOOLP192t1,
- BRAINPOOLP224t1,
- BRAINPOOLP256t1,
- BRAINPOOLP320t1,
- BRAINPOOLP384t1,
- BRAINPOOLP512t1,
- ]
- def find_curve(oid_curve):
- """Select a curve based on its OID
- :param tuple[int,...] oid_curve: ASN.1 Object Identifier of the
- curve to return, like ``(1, 2, 840, 10045, 3, 1, 7)`` for ``NIST256p``.
- :raises UnknownCurveError: When the oid doesn't match any of the supported
- curves
- :rtype: ~ecdsa.curves.Curve
- """
- for c in curves:
- if c.oid == oid_curve:
- return c
- raise UnknownCurveError(
- "I don't know about the curve with oid %s."
- "I only know about these: %s" % (oid_curve, [c.name for c in curves])
- )
- def curve_by_name(name):
- """Select a curve based on its name.
- Returns a :py:class:`~ecdsa.curves.Curve` object with a ``name`` name.
- Note that ``name`` is case-sensitve.
- :param str name: Name of the curve to return, like ``NIST256p`` or
- ``prime256v1``
- :raises UnknownCurveError: When the name doesn't match any of the supported
- curves
- :rtype: ~ecdsa.curves.Curve
- """
- for c in curves:
- if name == c.name or (c.openssl_name and name == c.openssl_name):
- return c
- raise UnknownCurveError(
- "Curve with name {0!r} unknown, only curves supported: {1}".format(
- name, [c.name for c in curves]
- )
- )
|