ECC.py 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2015, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. from __future__ import print_function
  31. import re
  32. import struct
  33. import binascii
  34. from Crypto.Util.py3compat import bord, tobytes, tostr, bchr, is_string
  35. from Crypto.Math.Numbers import Integer
  36. from Crypto.Util.asn1 import (DerObjectId, DerOctetString, DerSequence,
  37. DerBitString)
  38. from Crypto.PublicKey import (_expand_subject_public_key_info,
  39. _create_subject_public_key_info,
  40. _extract_subject_public_key_info)
  41. from Crypto.Hash import SHA512, SHAKE256
  42. from Crypto.Random import get_random_bytes
  43. from ._point import EccPoint, EccXPoint, _curves
  44. from ._point import CurveID as _CurveID
  45. class UnsupportedEccFeature(ValueError):
  46. pass
  47. class EccKey(object):
  48. r"""Class defining an ECC key.
  49. Do not instantiate directly.
  50. Use :func:`generate`, :func:`construct` or :func:`import_key` instead.
  51. :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_.
  52. :vartype curve: string
  53. :ivar pointQ: an ECC point representing the public component.
  54. :vartype pointQ: :class:`EccPoint` or :class:`EccXPoint`
  55. :ivar d: A scalar that represents the private component
  56. in NIST P curves. It is smaller than the
  57. order of the generator point.
  58. :vartype d: integer
  59. :ivar seed: A seed that represents the private component
  60. in Ed22519 (32 bytes), Curve25519 (32 bytes),
  61. Curve448 (56 bytes), Ed448 (57 bytes).
  62. :vartype seed: bytes
  63. """
  64. def __init__(self, **kwargs):
  65. """Create a new ECC key
  66. Keywords:
  67. curve : string
  68. The name of the curve.
  69. d : integer
  70. Mandatory for a private key one NIST P curves.
  71. It must be in the range ``[1..order-1]``.
  72. seed : bytes
  73. Mandatory for a private key on Ed25519 (32 bytes),
  74. Curve25519 (32 bytes), Curve448 (56 bytes) or Ed448 (57 bytes).
  75. point : EccPoint or EccXPoint
  76. Mandatory for a public key. If provided for a private key,
  77. the implementation will NOT check whether it matches ``d``.
  78. Only one parameter among ``d``, ``seed`` or ``point`` may be used.
  79. """
  80. kwargs_ = dict(kwargs)
  81. curve_name = kwargs_.pop("curve", None)
  82. self._d = kwargs_.pop("d", None)
  83. self._seed = kwargs_.pop("seed", None)
  84. self._point = kwargs_.pop("point", None)
  85. if curve_name is None and self._point:
  86. curve_name = self._point.curve
  87. if kwargs_:
  88. raise TypeError("Unknown parameters: " + str(kwargs_))
  89. if curve_name not in _curves:
  90. raise ValueError("Unsupported curve (%s)" % curve_name)
  91. self._curve = _curves[curve_name]
  92. self.curve = self._curve.canonical
  93. count = int(self._d is not None) + int(self._seed is not None)
  94. if count == 0:
  95. if self._point is None:
  96. raise ValueError("At lest one between parameters 'point', 'd' or 'seed' must be specified")
  97. return
  98. if count == 2:
  99. raise ValueError("Parameters d and seed are mutually exclusive")
  100. # NIST P curves work with d, EdDSA works with seed
  101. # RFC 8032, 5.1.5
  102. if self._curve.id == _CurveID.ED25519:
  103. if self._d is not None:
  104. raise ValueError("Parameter d can only be used with NIST P curves")
  105. if len(self._seed) != 32:
  106. raise ValueError("Parameter seed must be 32 bytes long for Ed25519")
  107. seed_hash = SHA512.new(self._seed).digest() # h
  108. self._prefix = seed_hash[32:]
  109. tmp = bytearray(seed_hash[:32])
  110. tmp[0] &= 0xF8
  111. tmp[31] = (tmp[31] & 0x7F) | 0x40
  112. self._d = Integer.from_bytes(tmp, byteorder='little')
  113. # RFC 8032, 5.2.5
  114. elif self._curve.id == _CurveID.ED448:
  115. if self._d is not None:
  116. raise ValueError("Parameter d can only be used with NIST P curves")
  117. if len(self._seed) != 57:
  118. raise ValueError("Parameter seed must be 57 bytes long for Ed448")
  119. seed_hash = SHAKE256.new(self._seed).read(114) # h
  120. self._prefix = seed_hash[57:]
  121. tmp = bytearray(seed_hash[:57])
  122. tmp[0] &= 0xFC
  123. tmp[55] |= 0x80
  124. tmp[56] = 0
  125. self._d = Integer.from_bytes(tmp, byteorder='little')
  126. # RFC 7748, 5
  127. elif self._curve.id == _CurveID.CURVE25519:
  128. if self._d is not None:
  129. raise ValueError("Parameter d can only be used with NIST P curves")
  130. if len(self._seed) != 32:
  131. raise ValueError("Parameter seed must be 32 bytes long for Curve25519")
  132. tmp = bytearray(self._seed)
  133. tmp[0] &= 0xF8
  134. tmp[31] = (tmp[31] & 0x7F) | 0x40
  135. self._d = Integer.from_bytes(tmp, byteorder='little')
  136. elif self._curve.id == _CurveID.CURVE448:
  137. if self._d is not None:
  138. raise ValueError("Parameter d can only be used with NIST P curves")
  139. if len(self._seed) != 56:
  140. raise ValueError("Parameter seed must be 56 bytes long for Curve448")
  141. tmp = bytearray(self._seed)
  142. tmp[0] &= 0xFC
  143. tmp[55] |= 0x80
  144. self._d = Integer.from_bytes(tmp, byteorder='little')
  145. else:
  146. if self._seed is not None:
  147. raise ValueError("Parameter 'seed' cannot be used with NIST P-curves")
  148. self._d = Integer(self._d)
  149. if not 1 <= self._d < self._curve.order:
  150. raise ValueError("Parameter d must be an integer smaller than the curve order")
  151. def __eq__(self, other):
  152. if not isinstance(other, EccKey):
  153. return False
  154. if other.has_private() != self.has_private():
  155. return False
  156. return other.pointQ == self.pointQ
  157. def __repr__(self):
  158. if self.has_private():
  159. if self._curve.is_edwards:
  160. extra = ", seed=%s" % tostr(binascii.hexlify(self._seed))
  161. else:
  162. extra = ", d=%d" % int(self._d)
  163. else:
  164. extra = ""
  165. if self._curve.id in (_CurveID.CURVE25519,
  166. _CurveID.CURVE448):
  167. x = self.pointQ.x
  168. result = "EccKey(curve='%s', point_x=%d%s)" % (self._curve.canonical, x, extra)
  169. else:
  170. x, y = self.pointQ.xy
  171. result = "EccKey(curve='%s', point_x=%d, point_y=%d%s)" % (self._curve.canonical, x, y, extra)
  172. return result
  173. def has_private(self):
  174. """``True`` if this key can be used for making signatures or decrypting data."""
  175. return self._d is not None
  176. # ECDSA
  177. def _sign(self, z, k):
  178. assert 0 < k < self._curve.order
  179. order = self._curve.order
  180. blind = Integer.random_range(min_inclusive=1,
  181. max_exclusive=order)
  182. blind_d = self._d * blind
  183. inv_blind_k = (blind * k).inverse(order)
  184. r = (self._curve.G * k).x % order
  185. s = inv_blind_k * (blind * z + blind_d * r) % order
  186. return (r, s)
  187. # ECDSA
  188. def _verify(self, z, rs):
  189. order = self._curve.order
  190. sinv = rs[1].inverse(order)
  191. point1 = self._curve.G * ((sinv * z) % order)
  192. point2 = self.pointQ * ((sinv * rs[0]) % order)
  193. return (point1 + point2).x == rs[0]
  194. @property
  195. def d(self):
  196. if not self.has_private():
  197. raise ValueError("This is not a private ECC key")
  198. return self._d
  199. @property
  200. def seed(self):
  201. if not self.has_private():
  202. raise ValueError("This is not a private ECC key")
  203. return self._seed
  204. @property
  205. def pointQ(self):
  206. if self._point is None:
  207. self._point = self._curve.G * self._d
  208. return self._point
  209. def public_key(self):
  210. """A matching ECC public key.
  211. Returns:
  212. a new :class:`EccKey` object
  213. """
  214. return EccKey(curve=self._curve.canonical, point=self.pointQ)
  215. def _export_SEC1(self, compress):
  216. if not self._curve.is_weierstrass:
  217. raise ValueError("SEC1 format is only supported for NIST P curves")
  218. # See 2.2 in RFC5480 and 2.3.3 in SEC1
  219. #
  220. # The first byte is:
  221. # - 0x02: compressed, only X-coordinate, Y-coordinate is even
  222. # - 0x03: compressed, only X-coordinate, Y-coordinate is odd
  223. # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate
  224. #
  225. # PAI is in theory encoded as 0x00.
  226. modulus_bytes = self.pointQ.size_in_bytes()
  227. if compress:
  228. if self.pointQ.y.is_odd():
  229. first_byte = b'\x03'
  230. else:
  231. first_byte = b'\x02'
  232. public_key = (first_byte +
  233. self.pointQ.x.to_bytes(modulus_bytes))
  234. else:
  235. public_key = (b'\x04' +
  236. self.pointQ.x.to_bytes(modulus_bytes) +
  237. self.pointQ.y.to_bytes(modulus_bytes))
  238. return public_key
  239. def _export_eddsa_public(self):
  240. x, y = self.pointQ.xy
  241. if self._curve.id == _CurveID.ED25519:
  242. result = bytearray(y.to_bytes(32, byteorder='little'))
  243. result[31] = ((x & 1) << 7) | result[31]
  244. elif self._curve.id == _CurveID.ED448:
  245. result = bytearray(y.to_bytes(57, byteorder='little'))
  246. result[56] = (x & 1) << 7
  247. else:
  248. raise ValueError("Not an EdDSA key to export")
  249. return bytes(result)
  250. def _export_montgomery_public(self):
  251. if not self._curve.is_montgomery:
  252. raise ValueError("Not a Montgomery key to export")
  253. x = self.pointQ.x
  254. field_size = self.pointQ.size_in_bytes()
  255. result = bytearray(x.to_bytes(field_size, byteorder='little'))
  256. return bytes(result)
  257. def _export_subjectPublicKeyInfo(self, compress):
  258. if self._curve.is_edwards:
  259. oid = self._curve.oid
  260. public_key = self._export_eddsa_public()
  261. params = None
  262. elif self._curve.is_montgomery:
  263. oid = self._curve.oid
  264. public_key = self._export_montgomery_public()
  265. params = None
  266. else:
  267. oid = "1.2.840.10045.2.1" # unrestricted
  268. public_key = self._export_SEC1(compress)
  269. params = DerObjectId(self._curve.oid)
  270. return _create_subject_public_key_info(oid,
  271. public_key,
  272. params)
  273. def _export_rfc5915_private_der(self, include_ec_params=True):
  274. assert self.has_private()
  275. # ECPrivateKey ::= SEQUENCE {
  276. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  277. # privateKey OCTET STRING,
  278. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  279. # publicKey [1] BIT STRING OPTIONAL
  280. # }
  281. # Public key - uncompressed form
  282. modulus_bytes = self.pointQ.size_in_bytes()
  283. public_key = (b'\x04' +
  284. self.pointQ.x.to_bytes(modulus_bytes) +
  285. self.pointQ.y.to_bytes(modulus_bytes))
  286. seq = [1,
  287. DerOctetString(self.d.to_bytes(modulus_bytes)),
  288. DerObjectId(self._curve.oid, explicit=0),
  289. DerBitString(public_key, explicit=1)]
  290. if not include_ec_params:
  291. del seq[2]
  292. return DerSequence(seq).encode()
  293. def _export_pkcs8(self, **kwargs):
  294. from Crypto.IO import PKCS8
  295. if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs:
  296. raise ValueError("At least the 'protection' parameter must be present")
  297. if self._seed is not None:
  298. oid = self._curve.oid
  299. private_key = DerOctetString(self._seed).encode()
  300. params = None
  301. else:
  302. oid = "1.2.840.10045.2.1" # unrestricted
  303. private_key = self._export_rfc5915_private_der(include_ec_params=False)
  304. params = DerObjectId(self._curve.oid)
  305. result = PKCS8.wrap(private_key,
  306. oid,
  307. key_params=params,
  308. **kwargs)
  309. return result
  310. def _export_public_pem(self, compress):
  311. from Crypto.IO import PEM
  312. encoded_der = self._export_subjectPublicKeyInfo(compress)
  313. return PEM.encode(encoded_der, "PUBLIC KEY")
  314. def _export_private_pem(self, passphrase, **kwargs):
  315. from Crypto.IO import PEM
  316. encoded_der = self._export_rfc5915_private_der()
  317. return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs)
  318. def _export_private_clear_pkcs8_in_clear_pem(self):
  319. from Crypto.IO import PEM
  320. encoded_der = self._export_pkcs8()
  321. return PEM.encode(encoded_der, "PRIVATE KEY")
  322. def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs):
  323. from Crypto.IO import PEM
  324. assert passphrase
  325. if 'protection' not in kwargs:
  326. raise ValueError("At least the 'protection' parameter should be present")
  327. encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs)
  328. return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY")
  329. def _export_openssh(self, compress):
  330. if self.has_private():
  331. raise ValueError("Cannot export OpenSSH private keys")
  332. desc = self._curve.openssh
  333. if desc is None:
  334. raise ValueError("Cannot export %s keys as OpenSSH" % self.curve)
  335. elif desc == "ssh-ed25519":
  336. public_key = self._export_eddsa_public()
  337. comps = (tobytes(desc), tobytes(public_key))
  338. else:
  339. modulus_bytes = self.pointQ.size_in_bytes()
  340. if compress:
  341. first_byte = 2 + self.pointQ.y.is_odd()
  342. public_key = (bchr(first_byte) +
  343. self.pointQ.x.to_bytes(modulus_bytes))
  344. else:
  345. public_key = (b'\x04' +
  346. self.pointQ.x.to_bytes(modulus_bytes) +
  347. self.pointQ.y.to_bytes(modulus_bytes))
  348. middle = desc.split("-")[2]
  349. comps = (tobytes(desc), tobytes(middle), public_key)
  350. blob = b"".join([struct.pack(">I", len(x)) + x for x in comps])
  351. return desc + " " + tostr(binascii.b2a_base64(blob))
  352. def export_key(self, **kwargs):
  353. """Export this ECC key.
  354. Args:
  355. format (string):
  356. The output format:
  357. - ``'DER'``. The key will be encoded in ASN.1 DER format (binary).
  358. For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure
  359. defined in `RFC5480`_ will be used.
  360. For a private key, the ASN.1 ``ECPrivateKey`` structure defined
  361. in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope,
  362. see the ``use_pkcs8`` flag below).
  363. - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII).
  364. - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format
  365. (ASCII, public keys only).
  366. - ``'SEC1'``. The public key (i.e., the EC point) will be encoded
  367. into ``bytes`` according to Section 2.3.3 of `SEC1`_
  368. (which is a subset of the older X9.62 ITU standard).
  369. Only for NIST P-curves.
  370. - ``'raw'``. The public key will be encoded as ``bytes``,
  371. without any metadata.
  372. * For NIST P-curves: equivalent to ``'SEC1'``.
  373. * For Ed25519 and Ed448: ``bytes`` in the format
  374. defined in `RFC8032`_.
  375. * For Curve25519 and Curve448: ``bytes`` in the format
  376. defined in `RFC7748`_.
  377. passphrase (bytes or string):
  378. (*Private keys only*) The passphrase to protect the
  379. private key.
  380. use_pkcs8 (boolean):
  381. (*Private keys only*)
  382. If ``True`` (default and recommended), the `PKCS#8`_ representation
  383. will be used.
  384. It must be ``True`` for Ed25519, Ed448, Curve25519, and Curve448.
  385. If ``False`` and a passphrase is present, the obsolete PEM
  386. encryption will be used.
  387. protection (string):
  388. When a private key is exported with password-protection
  389. and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be
  390. present,
  391. For all possible protection schemes,
  392. refer to :ref:`the encryption parameters of PKCS#8<enc_params>`.
  393. It is recommended to use ``'PBKDF2WithHMAC-SHA512AndAES128-CBC'``.
  394. compress (boolean):
  395. If ``True``, the method returns a more compact representation
  396. of the public key, with the X-coordinate only.
  397. If ``False`` (default), the method returns the full public key.
  398. This parameter is ignored for Ed25519/Ed448/Curve25519/Curve448,
  399. as compression is mandatory.
  400. prot_params (dict):
  401. When a private key is exported with password-protection
  402. and PKCS#8 (both ``DER`` and ``PEM`` formats), this dictionary
  403. contains the parameters to use to derive the encryption key
  404. from the passphrase.
  405. For all possible values,
  406. refer to :ref:`the encryption parameters of PKCS#8<enc_params>`.
  407. The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2,
  408. and ``{'iteration_count':131072}`` for scrypt.
  409. .. warning::
  410. If you don't provide a passphrase, the private key will be
  411. exported in the clear!
  412. .. note::
  413. When exporting a private key with password-protection and `PKCS#8`_
  414. (both ``DER`` and ``PEM`` formats), any extra parameters
  415. to ``export_key()`` will be passed to :mod:`Crypto.IO.PKCS8`.
  416. .. _PEM: http://www.ietf.org/rfc/rfc1421.txt
  417. .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt
  418. .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt
  419. .. _RFC5480: https://tools.ietf.org/html/rfc5480
  420. .. _SEC1: https://www.secg.org/sec1-v2.pdf
  421. .. _RFC7748: https://tools.ietf.org/html/rfc7748
  422. Returns:
  423. A multi-line string (for ``'PEM'`` and ``'OpenSSH'``) or
  424. ``bytes`` (for ``'DER'``, ``'SEC1'``, and ``'raw'``) with the encoded key.
  425. """
  426. args = kwargs.copy()
  427. ext_format = args.pop("format")
  428. if ext_format not in ("PEM", "DER", "OpenSSH", "SEC1", "raw"):
  429. raise ValueError("Unknown format '%s'" % ext_format)
  430. compress = args.pop("compress", False)
  431. if self.has_private():
  432. passphrase = args.pop("passphrase", None)
  433. if is_string(passphrase):
  434. passphrase = tobytes(passphrase)
  435. if not passphrase:
  436. raise ValueError("Empty passphrase")
  437. use_pkcs8 = args.pop("use_pkcs8", True)
  438. if use_pkcs8 is False:
  439. if self._curve.is_edwards:
  440. raise ValueError("'pkcs8' must be True for EdDSA curves")
  441. if self._curve.is_montgomery:
  442. raise ValueError("'pkcs8' must be True for Curve25519")
  443. if 'protection' in args:
  444. raise ValueError("'protection' is only supported for PKCS#8")
  445. if ext_format == "PEM":
  446. if use_pkcs8:
  447. if passphrase:
  448. return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args)
  449. else:
  450. return self._export_private_clear_pkcs8_in_clear_pem()
  451. else:
  452. return self._export_private_pem(passphrase, **args)
  453. elif ext_format == "DER":
  454. # DER
  455. if passphrase and not use_pkcs8:
  456. raise ValueError("Private keys can only be encrpyted with DER using PKCS#8")
  457. if use_pkcs8:
  458. return self._export_pkcs8(passphrase=passphrase, **args)
  459. else:
  460. return self._export_rfc5915_private_der()
  461. else:
  462. raise ValueError("Private keys cannot be exported "
  463. "in the '%s' format" % ext_format)
  464. else: # Public key
  465. if args:
  466. raise ValueError("Unexpected parameters: '%s'" % args)
  467. if ext_format == "PEM":
  468. return self._export_public_pem(compress)
  469. elif ext_format == "DER":
  470. return self._export_subjectPublicKeyInfo(compress)
  471. elif ext_format == "SEC1":
  472. return self._export_SEC1(compress)
  473. elif ext_format == "raw":
  474. if self._curve.is_edwards:
  475. return self._export_eddsa_public()
  476. elif self._curve.is_montgomery:
  477. return self._export_montgomery_public()
  478. else:
  479. return self._export_SEC1(compress)
  480. else:
  481. return self._export_openssh(compress)
  482. def generate(**kwargs):
  483. """Generate a new private key on the given curve.
  484. Args:
  485. curve (string):
  486. Mandatory. It must be a curve name defined in the `ECC table`_.
  487. randfunc (callable):
  488. Optional. The RNG to read randomness from.
  489. If ``None``, :func:`Crypto.Random.get_random_bytes` is used.
  490. """
  491. curve_name = kwargs.pop("curve")
  492. curve = _curves[curve_name]
  493. randfunc = kwargs.pop("randfunc", get_random_bytes)
  494. if kwargs:
  495. raise TypeError("Unknown parameters: " + str(kwargs))
  496. if _curves[curve_name].id == _CurveID.ED25519:
  497. seed = randfunc(32)
  498. new_key = EccKey(curve=curve_name, seed=seed)
  499. elif _curves[curve_name].id == _CurveID.ED448:
  500. seed = randfunc(57)
  501. new_key = EccKey(curve=curve_name, seed=seed)
  502. elif _curves[curve_name].id == _CurveID.CURVE25519:
  503. seed = randfunc(32)
  504. new_key = EccKey(curve=curve_name, seed=seed)
  505. _curves[curve_name].validate(new_key.pointQ)
  506. elif _curves[curve_name].id == _CurveID.CURVE448:
  507. seed = randfunc(56)
  508. new_key = EccKey(curve=curve_name, seed=seed)
  509. _curves[curve_name].validate(new_key.pointQ)
  510. else:
  511. d = Integer.random_range(min_inclusive=1,
  512. max_exclusive=curve.order,
  513. randfunc=randfunc)
  514. new_key = EccKey(curve=curve_name, d=d)
  515. return new_key
  516. def construct(**kwargs):
  517. """Build a new ECC key (private or public) starting
  518. from some base components.
  519. In most cases, you will already have an existing key
  520. which you can read in with :func:`import_key` instead
  521. of this function.
  522. Args:
  523. curve (string):
  524. Mandatory. The name of the elliptic curve, as defined in the `ECC table`_.
  525. d (integer):
  526. Mandatory for a private key and a NIST P-curve (e.g., P-256).
  527. It must be an integer in the range ``[1..order-1]``.
  528. seed (bytes):
  529. Mandatory for a private key and curves Ed25519 (32 bytes),
  530. Curve25519 (32 bytes), Curve448 (56 bytes) and Ed448 (57 bytes).
  531. point_x (integer):
  532. The X coordinate (affine) of the ECC point.
  533. Mandatory for a public key.
  534. point_y (integer):
  535. The Y coordinate (affine) of the ECC point.
  536. Mandatory for a public key,
  537. except for Curve25519 and Curve448.
  538. Returns:
  539. :class:`EccKey` : a new ECC key object
  540. """
  541. curve_name = kwargs["curve"]
  542. curve = _curves[curve_name]
  543. point_x = kwargs.pop("point_x", None)
  544. point_y = kwargs.pop("point_y", None)
  545. if "point" in kwargs:
  546. raise TypeError("Unknown keyword: point")
  547. if curve.id == _CurveID.CURVE25519:
  548. if point_x is not None:
  549. kwargs["point"] = EccXPoint(point_x, curve_name)
  550. new_key = EccKey(**kwargs)
  551. curve.validate(new_key.pointQ)
  552. elif curve.id == _CurveID.CURVE448:
  553. if point_x is not None:
  554. kwargs["point"] = EccXPoint(point_x, curve_name)
  555. new_key = EccKey(**kwargs)
  556. curve.validate(new_key.pointQ)
  557. else:
  558. if None not in (point_x, point_y):
  559. kwargs["point"] = EccPoint(point_x, point_y, curve_name)
  560. new_key = EccKey(**kwargs)
  561. # Validate that the private key matches the public one
  562. # because EccKey will not do that automatically
  563. if new_key.has_private() and 'point' in kwargs:
  564. pub_key = curve.G * new_key.d
  565. if pub_key.xy != (point_x, point_y):
  566. raise ValueError("Private and public ECC keys do not match")
  567. return new_key
  568. def _import_public_der(ec_point, curve_oid=None, curve_name=None):
  569. """Convert an encoded EC point into an EccKey object
  570. ec_point: byte string with the EC point (SEC1-encoded)
  571. curve_oid: string with the name the curve
  572. curve_name: string with the OID of the curve
  573. Either curve_id or curve_name must be specified
  574. """
  575. for _curve_name, curve in _curves.items():
  576. if curve_oid and curve.oid == curve_oid:
  577. break
  578. if curve_name == _curve_name:
  579. break
  580. else:
  581. if curve_oid:
  582. raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid)
  583. else:
  584. raise UnsupportedEccFeature("Unsupported ECC curve (%s)" % curve_name)
  585. # See 2.2 in RFC5480 and 2.3.3 in SEC1
  586. # The first byte is:
  587. # - 0x02: compressed, only X-coordinate, Y-coordinate is even
  588. # - 0x03: compressed, only X-coordinate, Y-coordinate is odd
  589. # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate
  590. #
  591. # PAI is in theory encoded as 0x00.
  592. modulus_bytes = curve.p.size_in_bytes()
  593. point_type = bord(ec_point[0])
  594. # Uncompressed point
  595. if point_type == 0x04:
  596. if len(ec_point) != (1 + 2 * modulus_bytes):
  597. raise ValueError("Incorrect EC point length")
  598. x = Integer.from_bytes(ec_point[1:modulus_bytes+1])
  599. y = Integer.from_bytes(ec_point[modulus_bytes+1:])
  600. # Compressed point
  601. elif point_type in (0x02, 0x03):
  602. if len(ec_point) != (1 + modulus_bytes):
  603. raise ValueError("Incorrect EC point length")
  604. x = Integer.from_bytes(ec_point[1:])
  605. # Right now, we only support Short Weierstrass curves
  606. y = (x**3 - x*3 + curve.b).sqrt(curve.p)
  607. if point_type == 0x02 and y.is_odd():
  608. y = curve.p - y
  609. if point_type == 0x03 and y.is_even():
  610. y = curve.p - y
  611. else:
  612. raise ValueError("Incorrect EC point encoding")
  613. return construct(curve=_curve_name, point_x=x, point_y=y)
  614. def _import_subjectPublicKeyInfo(encoded, *kwargs):
  615. """Convert a subjectPublicKeyInfo into an EccKey object"""
  616. # See RFC5480
  617. # Parse the generic subjectPublicKeyInfo structure
  618. oid, ec_point, params = _expand_subject_public_key_info(encoded)
  619. nist_p_oids = (
  620. "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted)
  621. "1.3.132.1.12", # id-ecDH
  622. "1.3.132.1.13" # id-ecMQV
  623. )
  624. eddsa_oids = {
  625. "1.3.101.112": ("Ed25519", _import_ed25519_public_key), # id-Ed25519
  626. "1.3.101.113": ("Ed448", _import_ed448_public_key) # id-Ed448
  627. }
  628. xdh_oids = {
  629. "1.3.101.110": ("Curve25519", _import_curve25519_public_key), # id-X25519
  630. "1.3.101.111": ("Curve448", _import_curve448_public_key), # id-X448
  631. }
  632. if oid in nist_p_oids:
  633. # See RFC5480
  634. # Parameters are mandatory and encoded as ECParameters
  635. # ECParameters ::= CHOICE {
  636. # namedCurve OBJECT IDENTIFIER
  637. # -- implicitCurve NULL
  638. # -- specifiedCurve SpecifiedECDomain
  639. # }
  640. # implicitCurve and specifiedCurve are not supported (as per RFC)
  641. if not params:
  642. raise ValueError("Missing ECC parameters for ECC OID %s" % oid)
  643. try:
  644. curve_oid = DerObjectId().decode(params).value
  645. except ValueError:
  646. raise ValueError("Error decoding namedCurve")
  647. # ECPoint ::= OCTET STRING
  648. return _import_public_der(ec_point, curve_oid=curve_oid)
  649. elif oid in eddsa_oids:
  650. # See RFC8410
  651. curve_name, import_eddsa_public_key = eddsa_oids[oid]
  652. # Parameters must be absent
  653. if params:
  654. raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid)
  655. x, y = import_eddsa_public_key(ec_point)
  656. return construct(point_x=x, point_y=y, curve=curve_name)
  657. elif oid in xdh_oids:
  658. curve_name, import_xdh_public_key = xdh_oids[oid]
  659. # Parameters must be absent
  660. if params:
  661. raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid)
  662. x = import_xdh_public_key(ec_point)
  663. return construct(point_x=x, curve=curve_name)
  664. else:
  665. raise UnsupportedEccFeature("Unsupported ECC OID: %s" % oid)
  666. def _import_rfc5915_der(encoded, passphrase, curve_oid=None):
  667. # See RFC5915 https://tools.ietf.org/html/rfc5915
  668. #
  669. # ECPrivateKey ::= SEQUENCE {
  670. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  671. # privateKey OCTET STRING,
  672. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  673. # publicKey [1] BIT STRING OPTIONAL
  674. # }
  675. ec_private_key = DerSequence().decode(encoded, nr_elements=(2, 3, 4))
  676. if ec_private_key[0] != 1:
  677. raise ValueError("Incorrect ECC private key version")
  678. scalar_bytes = DerOctetString().decode(ec_private_key[1]).payload
  679. next_element = 2
  680. # Try to decode 'parameters'
  681. if next_element < len(ec_private_key):
  682. try:
  683. parameters = DerObjectId(explicit=0).decode(ec_private_key[next_element]).value
  684. if curve_oid is not None and parameters != curve_oid:
  685. raise ValueError("Curve mismatch")
  686. curve_oid = parameters
  687. next_element += 1
  688. except ValueError:
  689. pass
  690. if curve_oid is None:
  691. raise ValueError("No curve found")
  692. for curve_name, curve in _curves.items():
  693. if curve.oid == curve_oid:
  694. break
  695. else:
  696. raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid)
  697. modulus_bytes = curve.p.size_in_bytes()
  698. if len(scalar_bytes) != modulus_bytes:
  699. raise ValueError("Private key is too small")
  700. # Try to decode 'publicKey'
  701. point_x = point_y = None
  702. if next_element < len(ec_private_key):
  703. try:
  704. public_key_enc = DerBitString(explicit=1).decode(ec_private_key[next_element]).value
  705. public_key = _import_public_der(public_key_enc, curve_oid=curve_oid)
  706. point_x = public_key.pointQ.x
  707. point_y = public_key.pointQ.y
  708. next_element += 1
  709. except ValueError:
  710. pass
  711. d = Integer.from_bytes(scalar_bytes)
  712. return construct(curve=curve_name, d=d, point_x=point_x, point_y=point_y)
  713. def _import_pkcs8(encoded, passphrase):
  714. from Crypto.IO import PKCS8
  715. algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase)
  716. nist_p_oids = (
  717. "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted)
  718. "1.3.132.1.12", # id-ecDH
  719. "1.3.132.1.13" # id-ecMQV
  720. )
  721. eddsa_oids = {
  722. "1.3.101.112": "Ed25519", # id-Ed25519
  723. "1.3.101.113": "Ed448", # id-Ed448
  724. }
  725. xdh_oids = {
  726. "1.3.101.110": "Curve25519", # id-X25519
  727. "1.3.101.111": "Curve448", # id-X448
  728. }
  729. if algo_oid in nist_p_oids:
  730. curve_oid = DerObjectId().decode(params).value
  731. return _import_rfc5915_der(private_key, passphrase, curve_oid)
  732. elif algo_oid in eddsa_oids:
  733. if params is not None:
  734. raise ValueError("EdDSA ECC private key must not have parameters")
  735. curve_oid = None
  736. seed = DerOctetString().decode(private_key).payload
  737. return construct(curve=eddsa_oids[algo_oid], seed=seed)
  738. elif algo_oid in xdh_oids:
  739. curve_name = xdh_oids[algo_oid]
  740. if params is not None:
  741. raise ValueError("%s ECC private key must not have parameters" %
  742. curve_name)
  743. curve_oid = None
  744. seed = DerOctetString().decode(private_key).payload
  745. return construct(curve=xdh_oids[algo_oid], seed=seed)
  746. else:
  747. raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid)
  748. def _import_x509_cert(encoded, *kwargs):
  749. sp_info = _extract_subject_public_key_info(encoded)
  750. return _import_subjectPublicKeyInfo(sp_info)
  751. def _import_der(encoded, passphrase):
  752. try:
  753. return _import_subjectPublicKeyInfo(encoded, passphrase)
  754. except UnsupportedEccFeature as err:
  755. raise err
  756. except (ValueError, TypeError, IndexError):
  757. pass
  758. try:
  759. return _import_x509_cert(encoded, passphrase)
  760. except UnsupportedEccFeature as err:
  761. raise err
  762. except (ValueError, TypeError, IndexError):
  763. pass
  764. try:
  765. return _import_rfc5915_der(encoded, passphrase)
  766. except UnsupportedEccFeature as err:
  767. raise err
  768. except (ValueError, TypeError, IndexError):
  769. pass
  770. try:
  771. return _import_pkcs8(encoded, passphrase)
  772. except UnsupportedEccFeature as err:
  773. raise err
  774. except (ValueError, TypeError, IndexError):
  775. pass
  776. raise ValueError("Not an ECC DER key")
  777. def _import_openssh_public(encoded):
  778. parts = encoded.split(b' ')
  779. if len(parts) not in (2, 3):
  780. raise ValueError("Not an openssh public key")
  781. try:
  782. keystring = binascii.a2b_base64(parts[1])
  783. keyparts = []
  784. while len(keystring) > 4:
  785. lk = struct.unpack(">I", keystring[:4])[0]
  786. keyparts.append(keystring[4:4 + lk])
  787. keystring = keystring[4 + lk:]
  788. if parts[0] != keyparts[0]:
  789. raise ValueError("Mismatch in openssh public key")
  790. # NIST P curves
  791. if parts[0].startswith(b"ecdsa-sha2-"):
  792. for curve_name, curve in _curves.items():
  793. if curve.openssh is None:
  794. continue
  795. if not curve.openssh.startswith("ecdsa-sha2"):
  796. continue
  797. middle = tobytes(curve.openssh.split("-")[2])
  798. if keyparts[1] == middle:
  799. break
  800. else:
  801. raise ValueError("Unsupported ECC curve: " + middle)
  802. ecc_key = _import_public_der(keyparts[2], curve_oid=curve.oid)
  803. # EdDSA
  804. elif parts[0] == b"ssh-ed25519":
  805. x, y = _import_ed25519_public_key(keyparts[1])
  806. ecc_key = construct(curve="Ed25519", point_x=x, point_y=y)
  807. else:
  808. raise ValueError("Unsupported SSH key type: " + parts[0])
  809. except (IndexError, TypeError, binascii.Error):
  810. raise ValueError("Error parsing SSH key type: " + parts[0])
  811. return ecc_key
  812. def _import_openssh_private_ecc(data, password):
  813. from ._openssh import (import_openssh_private_generic,
  814. read_bytes, read_string, check_padding)
  815. key_type, decrypted = import_openssh_private_generic(data, password)
  816. eddsa_keys = {
  817. "ssh-ed25519": ("Ed25519", _import_ed25519_public_key, 32),
  818. }
  819. # https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04
  820. if key_type.startswith("ecdsa-sha2"):
  821. ecdsa_curve_name, decrypted = read_string(decrypted)
  822. if ecdsa_curve_name not in _curves:
  823. raise UnsupportedEccFeature("Unsupported ECC curve %s" % ecdsa_curve_name)
  824. curve = _curves[ecdsa_curve_name]
  825. modulus_bytes = (curve.modulus_bits + 7) // 8
  826. public_key, decrypted = read_bytes(decrypted)
  827. if bord(public_key[0]) != 4:
  828. raise ValueError("Only uncompressed OpenSSH EC keys are supported")
  829. if len(public_key) != 2 * modulus_bytes + 1:
  830. raise ValueError("Incorrect public key length")
  831. point_x = Integer.from_bytes(public_key[1:1+modulus_bytes])
  832. point_y = Integer.from_bytes(public_key[1+modulus_bytes:])
  833. private_key, decrypted = read_bytes(decrypted)
  834. d = Integer.from_bytes(private_key)
  835. params = {'d': d, 'curve': ecdsa_curve_name}
  836. elif key_type in eddsa_keys:
  837. curve_name, import_eddsa_public_key, seed_len = eddsa_keys[key_type]
  838. public_key, decrypted = read_bytes(decrypted)
  839. point_x, point_y = import_eddsa_public_key(public_key)
  840. private_public_key, decrypted = read_bytes(decrypted)
  841. seed = private_public_key[:seed_len]
  842. params = {'seed': seed, 'curve': curve_name}
  843. else:
  844. raise ValueError("Unsupport SSH agent key type:" + key_type)
  845. _, padded = read_string(decrypted) # Comment
  846. check_padding(padded)
  847. return construct(point_x=point_x, point_y=point_y, **params)
  848. def _import_ed25519_public_key(encoded):
  849. """Import an Ed25519 ECC public key, encoded as raw bytes as described
  850. in RFC8032_.
  851. Args:
  852. encoded (bytes):
  853. The Ed25519 public key to import. It must be 32 bytes long.
  854. Returns:
  855. x and y (integer)
  856. Raises:
  857. ValueError: when the given key cannot be parsed.
  858. .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032
  859. """
  860. if len(encoded) != 32:
  861. raise ValueError("Incorrect length. Only Ed25519 public keys are supported.")
  862. p = Integer(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed) # 2**255 - 19
  863. d = 37095705934669439343138083508754565189542113879843219016388785533085940283555
  864. y = bytearray(encoded)
  865. x_lsb = y[31] >> 7
  866. y[31] &= 0x7F
  867. point_y = Integer.from_bytes(y, byteorder='little')
  868. if point_y >= p:
  869. raise ValueError("Invalid Ed25519 key (y)")
  870. if point_y == 1:
  871. return 0, 1
  872. u = (point_y**2 - 1) % p
  873. v = ((point_y**2 % p) * d + 1) % p
  874. try:
  875. v_inv = v.inverse(p)
  876. x2 = (u * v_inv) % p
  877. point_x = Integer._tonelli_shanks(x2, p)
  878. if (point_x & 1) != x_lsb:
  879. point_x = p - point_x
  880. except ValueError:
  881. raise ValueError("Invalid Ed25519 public key")
  882. return point_x, point_y
  883. def _import_curve25519_public_key(encoded):
  884. """Import a Curve25519 ECC public key,
  885. encoded as raw bytes as described in RFC7748_.
  886. Args:
  887. encoded (bytes):
  888. The Curve25519 public key to import. It must be 32 bytes long.
  889. Returns:
  890. x (integer)
  891. Raises:
  892. ValueError: when the given key cannot be parsed.
  893. .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748
  894. """
  895. if len(encoded) != 32:
  896. raise ValueError("Incorrect Curve25519 key length")
  897. x = bytearray(encoded)
  898. # RFC 7741, Section 5
  899. x[31] &= 0x7F
  900. point_x = Integer.from_bytes(x, byteorder='little')
  901. return point_x
  902. def _import_curve448_public_key(encoded):
  903. """Import a Curve448 ECC public key,
  904. encoded as raw bytes as described in RFC7748_.
  905. Args:
  906. encoded (bytes):
  907. The Curve448 public key to import. It must be 56 bytes long.
  908. Returns:
  909. x (integer)
  910. Raises:
  911. ValueError: when the given key cannot be parsed.
  912. .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748
  913. """
  914. if len(encoded) != 56:
  915. raise ValueError("Incorrect Curve448 key length")
  916. point_x = Integer.from_bytes(encoded, byteorder='little')
  917. return point_x
  918. def _import_ed448_public_key(encoded):
  919. """Import an Ed448 ECC public key, encoded as raw bytes as described
  920. in RFC8032_.
  921. Args:
  922. encoded (bytes):
  923. The Ed448 public key to import. It must be 57 bytes long.
  924. Returns:
  925. x and y (integer)
  926. Raises:
  927. ValueError: when the given key cannot be parsed.
  928. .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032
  929. """
  930. if len(encoded) != 57:
  931. raise ValueError("Incorrect length. Only Ed448 public keys are supported.")
  932. p = _curves['curve448'].p
  933. d = p - 39081
  934. y = encoded[:56]
  935. x_lsb = bord(encoded[56]) >> 7
  936. point_y = Integer.from_bytes(y, byteorder='little')
  937. if point_y >= p:
  938. raise ValueError("Invalid Ed448 key (y)")
  939. if point_y == 1:
  940. return 0, 1
  941. u = (point_y**2 - 1) % p
  942. v = ((point_y**2 % p) * d - 1) % p
  943. try:
  944. v_inv = v.inverse(p)
  945. x2 = (u * v_inv) % p
  946. point_x = Integer._tonelli_shanks(x2, p)
  947. if (point_x & 1) != x_lsb:
  948. point_x = p - point_x
  949. except ValueError:
  950. raise ValueError("Invalid Ed448 public key")
  951. return point_x, point_y
  952. def import_key(encoded, passphrase=None, curve_name=None):
  953. """Import an ECC key (public or private).
  954. Args:
  955. encoded (bytes or multi-line string):
  956. The ECC key to import.
  957. The function will try to automatically detect the right format.
  958. Supported formats for an ECC **public** key:
  959. * X.509 certificate: binary (DER) or ASCII (PEM).
  960. * X.509 ``subjectPublicKeyInfo``: binary (DER) or ASCII (PEM).
  961. * SEC1_ (or X9.62), as ``bytes``. NIST P curves only.
  962. You must also provide the ``curve_name`` (with a value from the `ECC table`_)
  963. * OpenSSH line, defined in RFC5656_ and RFC8709_ (ASCII).
  964. This is normally the content of files like ``~/.ssh/id_ecdsa.pub``.
  965. Supported formats for an ECC **private** key:
  966. * A binary ``ECPrivateKey`` structure, as defined in `RFC5915`_ (DER).
  967. NIST P curves only.
  968. * A `PKCS#8`_ structure (or the more recent Asymmetric Key
  969. Package, RFC5958_): binary (DER) or ASCII (PEM).
  970. * `OpenSSH 6.5`_ and newer versions (ASCII).
  971. Private keys can be in the clear or password-protected.
  972. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
  973. passphrase (byte string):
  974. The passphrase to use for decrypting a private key.
  975. Encryption may be applied protected at the PEM level (not recommended)
  976. or at the PKCS#8 level (recommended).
  977. This parameter is ignored if the key in input is not encrypted.
  978. curve_name (string):
  979. For a SEC1 encoding only. This is the name of the curve,
  980. as defined in the `ECC table`_.
  981. .. note::
  982. To import EdDSA private and public keys, when encoded as raw ``bytes``, use:
  983. * :func:`Crypto.Signature.eddsa.import_public_key`, or
  984. * :func:`Crypto.Signature.eddsa.import_private_key`.
  985. .. note::
  986. To import X25519/X448 private and public keys, when encoded as raw ``bytes``, use:
  987. * :func:`Crypto.Protocol.DH.import_x25519_public_key`
  988. * :func:`Crypto.Protocol.DH.import_x25519_private_key`
  989. * :func:`Crypto.Protocol.DH.import_x448_public_key`
  990. * :func:`Crypto.Protocol.DH.import_x448_private_key`
  991. Returns:
  992. :class:`EccKey` : a new ECC key object
  993. Raises:
  994. ValueError: when the given key cannot be parsed (possibly because
  995. the pass phrase is wrong).
  996. .. _RFC1421: https://datatracker.ietf.org/doc/html/rfc1421
  997. .. _RFC1423: https://datatracker.ietf.org/doc/html/rfc1423
  998. .. _RFC5915: https://datatracker.ietf.org/doc/html/rfc5915
  999. .. _RFC5656: https://datatracker.ietf.org/doc/html/rfc5656
  1000. .. _RFC8709: https://datatracker.ietf.org/doc/html/rfc8709
  1001. .. _RFC5958: https://datatracker.ietf.org/doc/html/rfc5958
  1002. .. _`PKCS#8`: https://datatracker.ietf.org/doc/html/rfc5208
  1003. .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf
  1004. .. _SEC1: https://www.secg.org/sec1-v2.pdf
  1005. """
  1006. from Crypto.IO import PEM
  1007. encoded = tobytes(encoded)
  1008. if passphrase is not None:
  1009. passphrase = tobytes(passphrase)
  1010. # PEM
  1011. if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'):
  1012. text_encoded = tostr(encoded)
  1013. openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase)
  1014. result = _import_openssh_private_ecc(openssh_encoded, passphrase)
  1015. return result
  1016. elif encoded.startswith(b'-----'):
  1017. text_encoded = tostr(encoded)
  1018. # Remove any EC PARAMETERS section
  1019. # Ignore its content because the curve type must be already given in the key
  1020. ecparams_start = "-----BEGIN EC PARAMETERS-----"
  1021. ecparams_end = "-----END EC PARAMETERS-----"
  1022. text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "",
  1023. text_encoded,
  1024. flags=re.DOTALL)
  1025. der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase)
  1026. if enc_flag:
  1027. passphrase = None
  1028. try:
  1029. result = _import_der(der_encoded, passphrase)
  1030. except UnsupportedEccFeature as uef:
  1031. raise uef
  1032. except ValueError:
  1033. raise ValueError("Invalid DER encoding inside the PEM file")
  1034. return result
  1035. # OpenSSH
  1036. if encoded.startswith((b'ecdsa-sha2-', b'ssh-ed25519')):
  1037. return _import_openssh_public(encoded)
  1038. # DER
  1039. if len(encoded) > 0 and bord(encoded[0]) == 0x30:
  1040. return _import_der(encoded, passphrase)
  1041. # SEC1
  1042. if len(encoded) > 0 and bord(encoded[0]) in (0x02, 0x03, 0x04):
  1043. if curve_name is None:
  1044. raise ValueError("No curve name was provided")
  1045. return _import_public_der(encoded, curve_name=curve_name)
  1046. raise ValueError("ECC key format is not supported")
  1047. if __name__ == "__main__":
  1048. import time
  1049. d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd
  1050. point = _curves['p256'].G.copy()
  1051. count = 3000
  1052. start = time.time()
  1053. for x in range(count):
  1054. pointX = point * d
  1055. print("(P-256 G)", (time.time() - start) / count * 1000, "ms")
  1056. start = time.time()
  1057. for x in range(count):
  1058. pointX = pointX * d
  1059. print("(P-256 arbitrary point)", (time.time() - start) / count * 1000, "ms")