ECC.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  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. import struct
  31. import binascii
  32. from Crypto.Util.py3compat import bord, tobytes, b, tostr, bchr
  33. from Crypto.Math.Numbers import Integer
  34. from Crypto.Random import get_random_bytes
  35. from Crypto.Util.asn1 import (DerObjectId, DerOctetString, DerSequence,
  36. DerBitString)
  37. from Crypto.IO import PKCS8, PEM
  38. from Crypto.PublicKey import (_expand_subject_public_key_info,
  39. _create_subject_public_key_info,
  40. _extract_subject_public_key_info)
  41. class _Curve(object):
  42. pass
  43. _curve = _Curve()
  44. _curve.p = Integer(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffL)
  45. _curve.b = Integer(0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b)
  46. _curve.order = Integer(0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551)
  47. _curve.Gx = Integer(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296)
  48. _curve.Gy = Integer(0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
  49. _curve.names = ("P-256", "prime256v1", "secp256r1")
  50. _curve.oid = "1.2.840.10045.3.1.7"
  51. class EccPoint(object):
  52. """A class to abstract a point over an Elliptic Curve.
  53. :ivar x: The X-coordinate of the ECC point
  54. :vartype x: integer
  55. :ivar y: The Y-coordinate of the ECC point
  56. :vartype y: integer
  57. """
  58. def __init__(self, x, y):
  59. self._x = Integer(x)
  60. self._y = Integer(y)
  61. # Buffers
  62. self._common = Integer(0)
  63. self._tmp1 = Integer(0)
  64. self._x3 = Integer(0)
  65. self._y3 = Integer(0)
  66. def set(self, point):
  67. self._x = Integer(point._x)
  68. self._y = Integer(point._y)
  69. return self
  70. def __eq__(self, point):
  71. return self._x == point._x and self._y == point._y
  72. def __neg__(self):
  73. if self.is_point_at_infinity():
  74. return self.point_at_infinity()
  75. return EccPoint(self._x, _curve.p - self._y)
  76. def copy(self):
  77. return EccPoint(self._x, self._y)
  78. def is_point_at_infinity(self):
  79. return not (self._x or self._y)
  80. @staticmethod
  81. def point_at_infinity():
  82. return EccPoint(0, 0)
  83. @property
  84. def x(self):
  85. if self.is_point_at_infinity():
  86. raise ValueError("Point at infinity")
  87. return self._x
  88. @property
  89. def y(self):
  90. if self.is_point_at_infinity():
  91. raise ValueError("Point at infinity")
  92. return self._y
  93. def double(self):
  94. """Double this point (in-place operation).
  95. :Return:
  96. :class:`EccPoint` : this same object (to enable chaining)
  97. """
  98. if not self._y:
  99. return self.point_at_infinity()
  100. common = self._common
  101. tmp1 = self._tmp1
  102. x3 = self._x3
  103. y3 = self._y3
  104. # common = (pow(self._x, 2, _curve.p) * 3 - 3) * (self._y << 1).inverse(_curve.p) % _curve.p
  105. common.set(self._x)
  106. common.inplace_pow(2, _curve.p)
  107. common *= 3
  108. common -= 3
  109. tmp1.set(self._y)
  110. tmp1 <<= 1
  111. tmp1.inplace_inverse(_curve.p)
  112. common *= tmp1
  113. common %= _curve.p
  114. # x3 = (pow(common, 2, _curve.p) - 2 * self._x) % _curve.p
  115. x3.set(common)
  116. x3.inplace_pow(2, _curve.p)
  117. x3 -= self._x
  118. x3 -= self._x
  119. while x3.is_negative():
  120. x3 += _curve.p
  121. # y3 = ((self._x - x3) * common - self._y) % _curve.p
  122. y3.set(self._x)
  123. y3 -= x3
  124. y3 *= common
  125. y3 -= self._y
  126. y3 %= _curve.p
  127. self._x.set(x3)
  128. self._y.set(y3)
  129. return self
  130. def __iadd__(self, point):
  131. """Add a second point to this one"""
  132. if self.is_point_at_infinity():
  133. return self.set(point)
  134. if point.is_point_at_infinity():
  135. return self
  136. if self == point:
  137. return self.double()
  138. if self._x == point._x:
  139. return self.set(self.point_at_infinity())
  140. common = self._common
  141. tmp1 = self._tmp1
  142. x3 = self._x3
  143. y3 = self._y3
  144. # common = (point._y - self._y) * (point._x - self._x).inverse(_curve.p) % _curve.p
  145. common.set(point._y)
  146. common -= self._y
  147. tmp1.set(point._x)
  148. tmp1 -= self._x
  149. tmp1.inplace_inverse(_curve.p)
  150. common *= tmp1
  151. common %= _curve.p
  152. # x3 = (pow(common, 2, _curve.p) - self._x - point._x) % _curve.p
  153. x3.set(common)
  154. x3.inplace_pow(2, _curve.p)
  155. x3 -= self._x
  156. x3 -= point._x
  157. while x3.is_negative():
  158. x3 += _curve.p
  159. # y3 = ((self._x - x3) * common - self._y) % _curve.p
  160. y3.set(self._x)
  161. y3 -= x3
  162. y3 *= common
  163. y3 -= self._y
  164. y3 %= _curve.p
  165. self._x.set(x3)
  166. self._y.set(y3)
  167. return self
  168. def __add__(self, point):
  169. """Return a new point, the addition of this one and another"""
  170. result = self.copy()
  171. result += point
  172. return result
  173. def __mul__(self, scalar):
  174. """Return a new point, the scalar product of this one"""
  175. if scalar < 0:
  176. raise ValueError("Scalar multiplication only defined for non-negative integers")
  177. # Trivial results
  178. if scalar == 0 or self.is_point_at_infinity():
  179. return self.point_at_infinity()
  180. elif scalar == 1:
  181. return self.copy()
  182. # Scalar randomization
  183. scalar_blind = Integer.random(exact_bits=64) * _curve.order + scalar
  184. # Montgomery key ladder
  185. r = [self.point_at_infinity().copy(), self.copy()]
  186. bit_size = int(scalar_blind.size_in_bits())
  187. scalar_int = int(scalar_blind)
  188. for i in range(bit_size, -1, -1):
  189. di = scalar_int >> i & 1
  190. r[di ^ 1] += r[di]
  191. r[di].double()
  192. return r[0]
  193. _curve.G = EccPoint(_curve.Gx, _curve.Gy)
  194. class EccKey(object):
  195. r"""Class defining an ECC key.
  196. Do not instantiate directly.
  197. Use :func:`generate`, :func:`construct` or :func:`import_key` instead.
  198. :ivar curve: The name of the ECC curve
  199. :vartype curve: string
  200. :ivar pointQ: an ECC point representating the public component
  201. :vartype pointQ: :class:`EccPoint`
  202. :ivar q: A scalar representating the private component
  203. :vartype q: integer
  204. """
  205. def __init__(self, **kwargs):
  206. """Create a new ECC key
  207. Keywords:
  208. curve : string
  209. It must be *"P-256"*, *"prime256v1"* or *"secp256r1"*.
  210. d : integer
  211. Only for a private key. It must be in the range ``[1..order-1]``.
  212. point : EccPoint
  213. Mandatory for a public key. If provided for a private key,
  214. the implementation will NOT check whether it matches ``d``.
  215. """
  216. kwargs_ = dict(kwargs)
  217. self.curve = kwargs_.pop("curve", None)
  218. self._d = kwargs_.pop("d", None)
  219. self._point = kwargs_.pop("point", None)
  220. if kwargs_:
  221. raise TypeError("Unknown parameters: " + str(kwargs_))
  222. if self.curve not in _curve.names:
  223. raise ValueError("Unsupported curve (%s)", self.curve)
  224. if self._d is None:
  225. if self._point is None:
  226. raise ValueError("Either private or public ECC component must be specified")
  227. else:
  228. self._d = Integer(self._d)
  229. if not 1 <= self._d < _curve.order:
  230. raise ValueError("Invalid ECC private component")
  231. def __eq__(self, other):
  232. if other.has_private() != self.has_private():
  233. return False
  234. return (other.pointQ.x == self.pointQ.x) and (other.pointQ.y == self.pointQ.y)
  235. def __repr__(self):
  236. if self.has_private():
  237. extra = ", d=%d" % int(self._d)
  238. else:
  239. extra = ""
  240. return "EccKey(curve='P-256', x=%d, y=%d%s)" %\
  241. (self.pointQ.x, self.pointQ.y, extra)
  242. def has_private(self):
  243. """``True`` if this key can be used for making signatures or decrypting data."""
  244. return self._d is not None
  245. def _sign(self, z, k):
  246. assert 0 < k < _curve.order
  247. blind = Integer.random_range(min_inclusive=1,
  248. max_exclusive=_curve.order)
  249. blind_d = self._d * blind
  250. inv_blind_k = (blind * k).inverse(_curve.order)
  251. r = (_curve.G * k).x % _curve.order
  252. s = inv_blind_k * (blind * z + blind_d * r) % _curve.order
  253. return (r, s)
  254. def _verify(self, z, rs):
  255. sinv = rs[1].inverse(_curve.order)
  256. point1 = _curve.G * ((sinv * z) % _curve.order)
  257. point2 = self.pointQ * ((sinv * rs[0]) % _curve.order)
  258. return (point1 + point2).x == rs[0]
  259. @property
  260. def d(self):
  261. if not self.has_private():
  262. raise ValueError("This is not a private ECC key")
  263. return self._d
  264. @property
  265. def pointQ(self):
  266. if self._point is None:
  267. self._point = _curve.G * self._d
  268. return self._point
  269. def public_key(self):
  270. """A matching ECC public key.
  271. Returns:
  272. a new :class:`EccKey` object
  273. """
  274. return EccKey(curve="P-256", point=self.pointQ)
  275. def _export_subjectPublicKeyInfo(self):
  276. # Uncompressed form
  277. order_bytes = _curve.order.size_in_bytes()
  278. public_key = (bchr(4) +
  279. self.pointQ.x.to_bytes(order_bytes) +
  280. self.pointQ.y.to_bytes(order_bytes))
  281. unrestricted_oid = "1.2.840.10045.2.1"
  282. return _create_subject_public_key_info(unrestricted_oid,
  283. public_key,
  284. DerObjectId(_curve.oid))
  285. def _export_private_der(self, include_ec_params=True):
  286. assert self.has_private()
  287. # ECPrivateKey ::= SEQUENCE {
  288. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  289. # privateKey OCTET STRING,
  290. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  291. # publicKey [1] BIT STRING OPTIONAL
  292. # }
  293. # Public key - uncompressed form
  294. order_bytes = _curve.order.size_in_bytes()
  295. public_key = (bchr(4) +
  296. self.pointQ.x.to_bytes(order_bytes) +
  297. self.pointQ.y.to_bytes(order_bytes))
  298. seq = [1,
  299. DerOctetString(self.d.to_bytes(order_bytes)),
  300. DerObjectId(_curve.oid, explicit=0),
  301. DerBitString(public_key, explicit=1)]
  302. if not include_ec_params:
  303. del seq[2]
  304. return DerSequence(seq).encode()
  305. def _export_pkcs8(self, **kwargs):
  306. if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs:
  307. raise ValueError("At least the 'protection' parameter should be present")
  308. unrestricted_oid = "1.2.840.10045.2.1"
  309. private_key = self._export_private_der(include_ec_params=False)
  310. result = PKCS8.wrap(private_key,
  311. unrestricted_oid,
  312. key_params=DerObjectId(_curve.oid),
  313. **kwargs)
  314. return result
  315. def _export_public_pem(self):
  316. encoded_der = self._export_subjectPublicKeyInfo()
  317. return PEM.encode(encoded_der, "PUBLIC KEY")
  318. def _export_private_pem(self, passphrase, **kwargs):
  319. encoded_der = self._export_private_der()
  320. return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs)
  321. def _export_private_clear_pkcs8_in_clear_pem(self):
  322. encoded_der = self._export_pkcs8()
  323. return PEM.encode(encoded_der, "PRIVATE KEY")
  324. def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs):
  325. assert passphrase
  326. if 'protection' not in kwargs:
  327. raise ValueError("At least the 'protection' parameter should be present")
  328. encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs)
  329. return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY")
  330. def _export_openssh(self):
  331. assert not self.has_private()
  332. desc = "ecdsa-sha2-nistp256"
  333. # Uncompressed form
  334. order_bytes = _curve.order.size_in_bytes()
  335. public_key = (bchr(4) +
  336. self.pointQ.x.to_bytes(order_bytes) +
  337. self.pointQ.y.to_bytes(order_bytes))
  338. comps = (tobytes(desc), b("nistp256"), public_key)
  339. blob = b("").join([ struct.pack(">I", len(x)) + x for x in comps])
  340. return desc + " " + tostr(binascii.b2a_base64(blob))
  341. def export_key(self, **kwargs):
  342. """Export this ECC key.
  343. Args:
  344. format (string):
  345. The format to use for wrapping the key:
  346. - *'DER'*. The key will be encoded in an ASN.1 DER_ structure (binary).
  347. - *'PEM'*. The key will be encoded in a PEM_ envelope (ASCII).
  348. - *'OpenSSH'*. The key will be encoded in the OpenSSH_ format
  349. (ASCII, public keys only).
  350. passphrase (byte string or string):
  351. The passphrase to use for protecting the private key.
  352. use_pkcs8 (boolean):
  353. If ``True`` (default and recommended), the `PKCS#8`_ representation
  354. will be used.
  355. If ``False``, the much weaker and `PEM encryption`_ mechanism will be used.
  356. protection (string):
  357. When a private key is exported with password-protection
  358. and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be
  359. present and be a valid algorithm supported by :mod:`Crypto.IO.PKCS8`.
  360. It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-CBC``.
  361. .. warning::
  362. If you don't provide a passphrase, the private key will be
  363. exported in the clear!
  364. .. note::
  365. When exporting a private key with password-protection and `PKCS#8`_
  366. (both ``DER`` and ``PEM`` formats), any extra parameters
  367. is passed to :mod:`Crypto.IO.PKCS8`.
  368. .. _DER: http://www.ietf.org/rfc/rfc5915.txt
  369. .. _PEM: http://www.ietf.org/rfc/rfc1421.txt
  370. .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt
  371. .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
  372. .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt
  373. Returns:
  374. A multi-line string (for PEM and OpenSSH) or bytes (for DER) with the encoded key.
  375. """
  376. args = kwargs.copy()
  377. ext_format = args.pop("format")
  378. if ext_format not in ("PEM", "DER", "OpenSSH"):
  379. raise ValueError("Unknown format '%s'" % ext_format)
  380. if self.has_private():
  381. passphrase = args.pop("passphrase", None)
  382. if isinstance(passphrase, basestring):
  383. passphrase = tobytes(passphrase)
  384. if not passphrase:
  385. raise ValueError("Empty passphrase")
  386. use_pkcs8 = args.pop("use_pkcs8", True)
  387. if ext_format == "PEM":
  388. if use_pkcs8:
  389. if passphrase:
  390. return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args)
  391. else:
  392. return self._export_private_clear_pkcs8_in_clear_pem()
  393. else:
  394. return self._export_private_pem(passphrase, **args)
  395. elif ext_format == "DER":
  396. # DER
  397. if passphrase and not use_pkcs8:
  398. raise ValueError("Private keys can only be encrpyted with DER using PKCS#8")
  399. if use_pkcs8:
  400. return self._export_pkcs8(passphrase=passphrase, **args)
  401. else:
  402. return self._export_private_der()
  403. else:
  404. raise ValueError("Private keys cannot be exported in OpenSSH format")
  405. else: # Public key
  406. if args:
  407. raise ValueError("Unexpected parameters: '%s'" % args)
  408. if ext_format == "PEM":
  409. return self._export_public_pem()
  410. elif ext_format == "DER":
  411. return self._export_subjectPublicKeyInfo()
  412. else:
  413. return self._export_openssh()
  414. def generate(**kwargs):
  415. """Generate a new private key on the given curve.
  416. Args:
  417. curve (string):
  418. Mandatory. It must be "P-256", "prime256v1" or "secp256r1".
  419. randfunc (callable):
  420. Optional. The RNG to read randomness from.
  421. If ``None``, :func:`Crypto.Random.get_random_bytes` is used.
  422. """
  423. curve = kwargs.pop("curve")
  424. randfunc = kwargs.pop("randfunc", get_random_bytes)
  425. if kwargs:
  426. raise TypeError("Unknown parameters: " + str(kwargs))
  427. d = Integer.random_range(min_inclusive=1,
  428. max_exclusive=_curve.order,
  429. randfunc=randfunc)
  430. return EccKey(curve=curve, d=d)
  431. def construct(**kwargs):
  432. """Build a new ECC key (private or public) starting
  433. from some base components.
  434. Args:
  435. curve (string):
  436. Mandatory. It must be "P-256", "prime256v1" or "secp256r1".
  437. d (integer):
  438. Only for a private key. It must be in the range ``[1..order-1]``.
  439. point_x (integer):
  440. Mandatory for a public key. X coordinate (affine) of the ECC point.
  441. point_y (integer):
  442. Mandatory for a public key. Y coordinate (affine) of the ECC point.
  443. Returns:
  444. :class:`EccKey` : a new ECC key object
  445. """
  446. point_x = kwargs.pop("point_x", None)
  447. point_y = kwargs.pop("point_y", None)
  448. if "point" in kwargs:
  449. raise TypeError("Unknown keyword: point")
  450. if None not in (point_x, point_y):
  451. kwargs["point"] = EccPoint(point_x, point_y)
  452. # Validate that the point is on the P-256 curve
  453. eq1 = pow(Integer(point_y), 2, _curve.p)
  454. x = Integer(point_x)
  455. eq2 = pow(x, 3, _curve.p)
  456. x *= -3
  457. eq2 += x
  458. eq2 += _curve.b
  459. eq2 %= _curve.p
  460. if eq1 != eq2:
  461. raise ValueError("The point is not on the curve")
  462. # Validate that the private key matches the public one
  463. d = kwargs.get("d", None)
  464. if d is not None and "point" in kwargs:
  465. pub_key = _curve.G * d
  466. if pub_key.x != point_x or pub_key.y != point_y:
  467. raise ValueError("Private and public ECC keys do not match")
  468. return EccKey(**kwargs)
  469. def _import_public_der(curve_name, publickey):
  470. # We only support P-256 named curves for now
  471. if curve_name != _curve.oid:
  472. raise ValueError("Unsupport curve")
  473. # ECPoint ::= OCTET STRING
  474. # We support only uncompressed points
  475. order_bytes = _curve.order.size_in_bytes()
  476. if len(publickey) != (1 + 2 * order_bytes) or bord(publickey[0]) != 4:
  477. raise ValueError("Only uncompressed points are supported")
  478. point_x = Integer.from_bytes(publickey[1:order_bytes+1])
  479. point_y = Integer.from_bytes(publickey[order_bytes+1:])
  480. return construct(curve="P-256", point_x=point_x, point_y=point_y)
  481. def _import_subjectPublicKeyInfo(encoded, *kwargs):
  482. oid, encoded_key, params = _expand_subject_public_key_info(encoded)
  483. # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any
  484. # distiction for now.
  485. unrestricted_oid = "1.2.840.10045.2.1"
  486. ecdh_oid = "1.3.132.1.12"
  487. ecmqv_oid = "1.3.132.1.13"
  488. if oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid) or not params:
  489. raise ValueError("Invalid ECC OID")
  490. # ECParameters ::= CHOICE {
  491. # namedCurve OBJECT IDENTIFIER
  492. # -- implicitCurve NULL
  493. # -- specifiedCurve SpecifiedECDomain
  494. # }
  495. curve_name = DerObjectId().decode(params).value
  496. return _import_public_der(curve_name, encoded_key)
  497. def _import_private_der(encoded, passphrase, curve_name=None):
  498. # ECPrivateKey ::= SEQUENCE {
  499. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  500. # privateKey OCTET STRING,
  501. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  502. # publicKey [1] BIT STRING OPTIONAL
  503. # }
  504. private_key = DerSequence().decode(encoded, nr_elements=(3, 4))
  505. if private_key[0] != 1:
  506. raise ValueError("Incorrect ECC private key version")
  507. scalar_bytes = DerOctetString().decode(private_key[1]).payload
  508. order_bytes = _curve.order.size_in_bytes()
  509. if len(scalar_bytes) != order_bytes:
  510. raise ValueError("Private key is too small")
  511. d = Integer.from_bytes(scalar_bytes)
  512. try:
  513. curve_name = DerObjectId(explicit=0).decode(private_key[2]).value
  514. except ValueError:
  515. pass
  516. if curve_name != _curve.oid:
  517. raise ValueError("Unsupport curve")
  518. # Decode public key (if any, it must be P-256)
  519. if len(private_key) == 4:
  520. public_key_enc = DerBitString(explicit=1).decode(private_key[3]).value
  521. public_key = _import_public_der(curve_name, public_key_enc)
  522. point_x = public_key.pointQ.x
  523. point_y = public_key.pointQ.y
  524. else:
  525. point_x = point_y = None
  526. return construct(curve="P-256", d=d, point_x=point_x, point_y=point_y)
  527. def _import_pkcs8(encoded, passphrase):
  528. # From RFC5915, Section 1:
  529. #
  530. # Distributing an EC private key with PKCS#8 [RFC5208] involves including:
  531. # a) id-ecPublicKey, id-ecDH, or id-ecMQV (from [RFC5480]) with the
  532. # namedCurve as the parameters in the privateKeyAlgorithm field; and
  533. # b) ECPrivateKey in the PrivateKey field, which is an OCTET STRING.
  534. algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase)
  535. # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any
  536. # distiction for now.
  537. unrestricted_oid = "1.2.840.10045.2.1"
  538. ecdh_oid = "1.3.132.1.12"
  539. ecmqv_oid = "1.3.132.1.13"
  540. if algo_oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid):
  541. raise ValueError("No PKCS#8 encoded ECC key")
  542. curve_name = DerObjectId().decode(params).value
  543. return _import_private_der(private_key, passphrase, curve_name)
  544. def _import_x509_cert(encoded, *kwargs):
  545. sp_info = _extract_subject_public_key_info(encoded)
  546. return _import_subjectPublicKeyInfo(sp_info)
  547. def _import_der(encoded, passphrase):
  548. decodings = (
  549. _import_subjectPublicKeyInfo,
  550. _import_x509_cert,
  551. _import_private_der,
  552. _import_pkcs8,
  553. )
  554. for decoding in decodings:
  555. try:
  556. return decoding(encoded, passphrase)
  557. except (ValueError, TypeError, IndexError):
  558. pass
  559. raise ValueError("Not an ECC DER key")
  560. def _import_openssh(encoded):
  561. keystring = binascii.a2b_base64(encoded.split(b(' '))[1])
  562. keyparts = []
  563. while len(keystring) > 4:
  564. l = struct.unpack(">I", keystring[:4])[0]
  565. keyparts.append(keystring[4:4 + l])
  566. keystring = keystring[4 + l:]
  567. if keyparts[1] != b("nistp256"):
  568. raise ValueError("Unsupported ECC curve")
  569. return _import_public_der(_curve.oid, keyparts[2])
  570. def import_key(encoded, passphrase=None):
  571. """Import an ECC key (public or private).
  572. Args:
  573. encoded (bytes or multi-line string):
  574. The ECC key to import.
  575. An ECC **public** key can be:
  576. - An X.509 certificate, binary (DER) or ASCII (PEM)
  577. - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM)
  578. - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII)
  579. An ECC **private** key can be:
  580. - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_)
  581. - In ASCII format (PEM or OpenSSH)
  582. Private keys can be in the clear or password-protected.
  583. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
  584. passphrase (byte string):
  585. The passphrase to use for decrypting a private key.
  586. Encryption may be applied protected at the PEM level or at the PKCS#8 level.
  587. This parameter is ignored if the key in input is not encrypted.
  588. Returns:
  589. :class:`EccKey` : a new ECC key object
  590. Raises:
  591. ValueError: when the given key cannot be parsed (possibly because
  592. the pass phrase is wrong).
  593. .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
  594. .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
  595. .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt
  596. .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
  597. """
  598. encoded = tobytes(encoded)
  599. if passphrase is not None:
  600. passphrase = tobytes(passphrase)
  601. # PEM
  602. if encoded.startswith(b('-----')):
  603. der_encoded, marker, enc_flag = PEM.decode(tostr(encoded), passphrase)
  604. if enc_flag:
  605. passphrase = None
  606. return _import_der(der_encoded, passphrase)
  607. # OpenSSH
  608. if encoded.startswith(b('ecdsa-sha2-')):
  609. return _import_openssh(encoded)
  610. # DER
  611. if bord(encoded[0]) == 0x30:
  612. return _import_der(encoded, passphrase)
  613. raise ValueError("ECC key format is not supported")
  614. if __name__ == "__main__":
  615. import time
  616. d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd
  617. point = generate(curve="P-256").pointQ
  618. start = time.time()
  619. count = 30
  620. for x in xrange(count):
  621. _ = point * d
  622. print (time.time() - start) / count * 1000, "ms"