ECC.py 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818
  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 collections import namedtuple
  35. from Crypto.Util.py3compat import bord, tobytes, tostr, bchr, is_string
  36. from Crypto.Util.number import bytes_to_long, long_to_bytes
  37. from Crypto.Math.Numbers import Integer
  38. from Crypto.Util.asn1 import (DerObjectId, DerOctetString, DerSequence,
  39. DerBitString)
  40. from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer,
  41. SmartPointer, c_size_t, c_uint8_ptr,
  42. c_ulonglong, null_pointer)
  43. from Crypto.PublicKey import (_expand_subject_public_key_info,
  44. _create_subject_public_key_info,
  45. _extract_subject_public_key_info)
  46. from Crypto.Hash import SHA512, SHAKE256
  47. from Crypto.Random import get_random_bytes
  48. from Crypto.Random.random import getrandbits
  49. _ec_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ec_ws", """
  50. typedef void EcContext;
  51. typedef void EcPoint;
  52. int ec_ws_new_context(EcContext **pec_ctx,
  53. const uint8_t *modulus,
  54. const uint8_t *b,
  55. const uint8_t *order,
  56. size_t len,
  57. uint64_t seed);
  58. void ec_free_context(EcContext *ec_ctx);
  59. int ec_ws_new_point(EcPoint **pecp,
  60. const uint8_t *x,
  61. const uint8_t *y,
  62. size_t len,
  63. const EcContext *ec_ctx);
  64. void ec_ws_free_point(EcPoint *ecp);
  65. int ec_ws_get_xy(uint8_t *x,
  66. uint8_t *y,
  67. size_t len,
  68. const EcPoint *ecp);
  69. int ec_ws_double(EcPoint *p);
  70. int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb);
  71. int ec_ws_scalar(EcPoint *ecp,
  72. const uint8_t *k,
  73. size_t len,
  74. uint64_t seed);
  75. int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp);
  76. int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2);
  77. int ec_ws_neg(EcPoint *p);
  78. """)
  79. _ed25519_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ed25519", """
  80. typedef void Point;
  81. int ed25519_new_point(Point **out,
  82. const uint8_t x[32],
  83. const uint8_t y[32],
  84. size_t modsize,
  85. const void *context);
  86. int ed25519_clone(Point **P, const Point *Q);
  87. void ed25519_free_point(Point *p);
  88. int ed25519_cmp(const Point *p1, const Point *p2);
  89. int ed25519_neg(Point *p);
  90. int ed25519_get_xy(uint8_t *xb, uint8_t *yb, size_t modsize, Point *p);
  91. int ed25519_double(Point *p);
  92. int ed25519_add(Point *P1, const Point *P2);
  93. int ed25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed);
  94. """)
  95. _ed448_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ed448", """
  96. typedef void EcContext;
  97. typedef void PointEd448;
  98. int ed448_new_context(EcContext **pec_ctx);
  99. void ed448_context(EcContext *ec_ctx);
  100. void ed448_free_context(EcContext *ec_ctx);
  101. int ed448_new_point(PointEd448 **out,
  102. const uint8_t x[56],
  103. const uint8_t y[56],
  104. size_t len,
  105. const EcContext *context);
  106. int ed448_clone(PointEd448 **P, const PointEd448 *Q);
  107. void ed448_free_point(PointEd448 *p);
  108. int ed448_cmp(const PointEd448 *p1, const PointEd448 *p2);
  109. int ed448_neg(PointEd448 *p);
  110. int ed448_get_xy(uint8_t *xb, uint8_t *yb, size_t len, const PointEd448 *p);
  111. int ed448_double(PointEd448 *p);
  112. int ed448_add(PointEd448 *P1, const PointEd448 *P2);
  113. int ed448_scalar(PointEd448 *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed);
  114. """)
  115. def lib_func(ecc_obj, func_name):
  116. if ecc_obj._curve.desc == "Ed25519":
  117. result = getattr(_ed25519_lib, "ed25519_" + func_name)
  118. elif ecc_obj._curve.desc == "Ed448":
  119. result = getattr(_ed448_lib, "ed448_" + func_name)
  120. else:
  121. result = getattr(_ec_lib, "ec_ws_" + func_name)
  122. return result
  123. #
  124. # _curves is a database of curve parameters. Items are indexed by their
  125. # human-friendly name, suchas "P-256". Each item has the following fields:
  126. # - p: the prime number that defines the finite field for all modulo operations
  127. # - b: the constant in the Short Weierstrass curve equation
  128. # - order: the number of elements in the group with the generator below
  129. # - Gx the affine coordinate X of the generator point
  130. # - Gy the affine coordinate Y of the generator point
  131. # - G the generator, as an EccPoint object
  132. # - modulus_bits the minimum number of bits for encoding the modulus p
  133. # - oid an ASCII string with the registered ASN.1 Object ID
  134. # - context a raw pointer to memory holding a context for all curve operations (can be NULL)
  135. # - desc an ASCII string describing the curve
  136. # - openssh the ASCII string used in OpenSSH id files for public keys on this curve
  137. # - name the ASCII string which is also a valid key in _curves
  138. _Curve = namedtuple("_Curve", "p b order Gx Gy G modulus_bits oid context desc openssh name")
  139. _curves = {}
  140. p192_names = ["p192", "NIST P-192", "P-192", "prime192v1", "secp192r1",
  141. "nistp192"]
  142. def init_p192():
  143. p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff
  144. b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
  145. order = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831
  146. Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
  147. Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811
  148. p192_modulus = long_to_bytes(p, 24)
  149. p192_b = long_to_bytes(b, 24)
  150. p192_order = long_to_bytes(order, 24)
  151. ec_p192_context = VoidPointer()
  152. result = _ec_lib.ec_ws_new_context(ec_p192_context.address_of(),
  153. c_uint8_ptr(p192_modulus),
  154. c_uint8_ptr(p192_b),
  155. c_uint8_ptr(p192_order),
  156. c_size_t(len(p192_modulus)),
  157. c_ulonglong(getrandbits(64))
  158. )
  159. if result:
  160. raise ImportError("Error %d initializing P-192 context" % result)
  161. context = SmartPointer(ec_p192_context.get(), _ec_lib.ec_free_context)
  162. p192 = _Curve(Integer(p),
  163. Integer(b),
  164. Integer(order),
  165. Integer(Gx),
  166. Integer(Gy),
  167. None,
  168. 192,
  169. "1.2.840.10045.3.1.1", # ANSI X9.62 / SEC2
  170. context,
  171. "NIST P-192",
  172. "ecdsa-sha2-nistp192",
  173. "p192")
  174. global p192_names
  175. _curves.update(dict.fromkeys(p192_names, p192))
  176. init_p192()
  177. del init_p192
  178. p224_names = ["p224", "NIST P-224", "P-224", "prime224v1", "secp224r1",
  179. "nistp224"]
  180. def init_p224():
  181. p = 0xffffffffffffffffffffffffffffffff000000000000000000000001
  182. b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4
  183. order = 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d
  184. Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21
  185. Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34
  186. p224_modulus = long_to_bytes(p, 28)
  187. p224_b = long_to_bytes(b, 28)
  188. p224_order = long_to_bytes(order, 28)
  189. ec_p224_context = VoidPointer()
  190. result = _ec_lib.ec_ws_new_context(ec_p224_context.address_of(),
  191. c_uint8_ptr(p224_modulus),
  192. c_uint8_ptr(p224_b),
  193. c_uint8_ptr(p224_order),
  194. c_size_t(len(p224_modulus)),
  195. c_ulonglong(getrandbits(64))
  196. )
  197. if result:
  198. raise ImportError("Error %d initializing P-224 context" % result)
  199. context = SmartPointer(ec_p224_context.get(), _ec_lib.ec_free_context)
  200. p224 = _Curve(Integer(p),
  201. Integer(b),
  202. Integer(order),
  203. Integer(Gx),
  204. Integer(Gy),
  205. None,
  206. 224,
  207. "1.3.132.0.33", # SEC 2
  208. context,
  209. "NIST P-224",
  210. "ecdsa-sha2-nistp224",
  211. "p224")
  212. global p224_names
  213. _curves.update(dict.fromkeys(p224_names, p224))
  214. init_p224()
  215. del init_p224
  216. p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1",
  217. "nistp256"]
  218. def init_p256():
  219. p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
  220. b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
  221. order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
  222. Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
  223. Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
  224. p256_modulus = long_to_bytes(p, 32)
  225. p256_b = long_to_bytes(b, 32)
  226. p256_order = long_to_bytes(order, 32)
  227. ec_p256_context = VoidPointer()
  228. result = _ec_lib.ec_ws_new_context(ec_p256_context.address_of(),
  229. c_uint8_ptr(p256_modulus),
  230. c_uint8_ptr(p256_b),
  231. c_uint8_ptr(p256_order),
  232. c_size_t(len(p256_modulus)),
  233. c_ulonglong(getrandbits(64))
  234. )
  235. if result:
  236. raise ImportError("Error %d initializing P-256 context" % result)
  237. context = SmartPointer(ec_p256_context.get(), _ec_lib.ec_free_context)
  238. p256 = _Curve(Integer(p),
  239. Integer(b),
  240. Integer(order),
  241. Integer(Gx),
  242. Integer(Gy),
  243. None,
  244. 256,
  245. "1.2.840.10045.3.1.7", # ANSI X9.62 / SEC2
  246. context,
  247. "NIST P-256",
  248. "ecdsa-sha2-nistp256",
  249. "p256")
  250. global p256_names
  251. _curves.update(dict.fromkeys(p256_names, p256))
  252. init_p256()
  253. del init_p256
  254. p384_names = ["p384", "NIST P-384", "P-384", "prime384v1", "secp384r1",
  255. "nistp384"]
  256. def init_p384():
  257. p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff
  258. b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef
  259. order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973
  260. Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7
  261. Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F
  262. p384_modulus = long_to_bytes(p, 48)
  263. p384_b = long_to_bytes(b, 48)
  264. p384_order = long_to_bytes(order, 48)
  265. ec_p384_context = VoidPointer()
  266. result = _ec_lib.ec_ws_new_context(ec_p384_context.address_of(),
  267. c_uint8_ptr(p384_modulus),
  268. c_uint8_ptr(p384_b),
  269. c_uint8_ptr(p384_order),
  270. c_size_t(len(p384_modulus)),
  271. c_ulonglong(getrandbits(64))
  272. )
  273. if result:
  274. raise ImportError("Error %d initializing P-384 context" % result)
  275. context = SmartPointer(ec_p384_context.get(), _ec_lib.ec_free_context)
  276. p384 = _Curve(Integer(p),
  277. Integer(b),
  278. Integer(order),
  279. Integer(Gx),
  280. Integer(Gy),
  281. None,
  282. 384,
  283. "1.3.132.0.34", # SEC 2
  284. context,
  285. "NIST P-384",
  286. "ecdsa-sha2-nistp384",
  287. "p384")
  288. global p384_names
  289. _curves.update(dict.fromkeys(p384_names, p384))
  290. init_p384()
  291. del init_p384
  292. p521_names = ["p521", "NIST P-521", "P-521", "prime521v1", "secp521r1",
  293. "nistp521"]
  294. def init_p521():
  295. p = 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
  296. b = 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00
  297. order = 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409
  298. Gx = 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66
  299. Gy = 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650
  300. p521_modulus = long_to_bytes(p, 66)
  301. p521_b = long_to_bytes(b, 66)
  302. p521_order = long_to_bytes(order, 66)
  303. ec_p521_context = VoidPointer()
  304. result = _ec_lib.ec_ws_new_context(ec_p521_context.address_of(),
  305. c_uint8_ptr(p521_modulus),
  306. c_uint8_ptr(p521_b),
  307. c_uint8_ptr(p521_order),
  308. c_size_t(len(p521_modulus)),
  309. c_ulonglong(getrandbits(64))
  310. )
  311. if result:
  312. raise ImportError("Error %d initializing P-521 context" % result)
  313. context = SmartPointer(ec_p521_context.get(), _ec_lib.ec_free_context)
  314. p521 = _Curve(Integer(p),
  315. Integer(b),
  316. Integer(order),
  317. Integer(Gx),
  318. Integer(Gy),
  319. None,
  320. 521,
  321. "1.3.132.0.35", # SEC 2
  322. context,
  323. "NIST P-521",
  324. "ecdsa-sha2-nistp521",
  325. "p521")
  326. global p521_names
  327. _curves.update(dict.fromkeys(p521_names, p521))
  328. init_p521()
  329. del init_p521
  330. ed25519_names = ["ed25519", "Ed25519"]
  331. def init_ed25519():
  332. p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19
  333. order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
  334. Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a
  335. Gy = 0x6666666666666666666666666666666666666666666666666666666666666658
  336. ed25519 = _Curve(Integer(p),
  337. None,
  338. Integer(order),
  339. Integer(Gx),
  340. Integer(Gy),
  341. None,
  342. 255,
  343. "1.3.101.112", # RFC8410
  344. None,
  345. "Ed25519", # Used throughout; do not change
  346. "ssh-ed25519",
  347. "ed25519")
  348. global ed25519_names
  349. _curves.update(dict.fromkeys(ed25519_names, ed25519))
  350. init_ed25519()
  351. del init_ed25519
  352. ed448_names = ["ed448", "Ed448"]
  353. def init_ed448():
  354. p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1
  355. order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3
  356. Gx = 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e
  357. Gy = 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14
  358. ed448_context = VoidPointer()
  359. result = _ed448_lib.ed448_new_context(ed448_context.address_of())
  360. if result:
  361. raise ImportError("Error %d initializing Ed448 context" % result)
  362. context = SmartPointer(ed448_context.get(), _ed448_lib.ed448_free_context)
  363. ed448 = _Curve(Integer(p),
  364. None,
  365. Integer(order),
  366. Integer(Gx),
  367. Integer(Gy),
  368. None,
  369. 448,
  370. "1.3.101.113", # RFC8410
  371. context,
  372. "Ed448", # Used throughout; do not change
  373. None,
  374. "ed448")
  375. global ed448_names
  376. _curves.update(dict.fromkeys(ed448_names, ed448))
  377. init_ed448()
  378. del init_ed448
  379. class UnsupportedEccFeature(ValueError):
  380. pass
  381. class EccPoint(object):
  382. """A class to model a point on an Elliptic Curve.
  383. The class supports operators for:
  384. * Adding two points: ``R = S + T``
  385. * In-place addition: ``S += T``
  386. * Negating a point: ``R = -T``
  387. * Comparing two points: ``if S == T: ...`` or ``if S != T: ...``
  388. * Multiplying a point by a scalar: ``R = S*k``
  389. * In-place multiplication by a scalar: ``T *= k``
  390. :ivar x: The affine X-coordinate of the ECC point
  391. :vartype x: integer
  392. :ivar y: The affine Y-coordinate of the ECC point
  393. :vartype y: integer
  394. :ivar xy: The tuple with affine X- and Y- coordinates
  395. """
  396. def __init__(self, x, y, curve="p256"):
  397. try:
  398. self._curve = _curves[curve]
  399. except KeyError:
  400. raise ValueError("Unknown curve name %s" % str(curve))
  401. self._curve_name = curve
  402. modulus_bytes = self.size_in_bytes()
  403. xb = long_to_bytes(x, modulus_bytes)
  404. yb = long_to_bytes(y, modulus_bytes)
  405. if len(xb) != modulus_bytes or len(yb) != modulus_bytes:
  406. raise ValueError("Incorrect coordinate length")
  407. new_point = lib_func(self, "new_point")
  408. free_func = lib_func(self, "free_point")
  409. self._point = VoidPointer()
  410. try:
  411. context = self._curve.context.get()
  412. except AttributeError:
  413. context = null_pointer
  414. result = new_point(self._point.address_of(),
  415. c_uint8_ptr(xb),
  416. c_uint8_ptr(yb),
  417. c_size_t(modulus_bytes),
  418. context)
  419. if result:
  420. if result == 15:
  421. raise ValueError("The EC point does not belong to the curve")
  422. raise ValueError("Error %d while instantiating an EC point" % result)
  423. # Ensure that object disposal of this Python object will (eventually)
  424. # free the memory allocated by the raw library for the EC point
  425. self._point = SmartPointer(self._point.get(), free_func)
  426. def set(self, point):
  427. clone = lib_func(self, "clone")
  428. free_func = lib_func(self, "free_point")
  429. self._point = VoidPointer()
  430. result = clone(self._point.address_of(),
  431. point._point.get())
  432. if result:
  433. raise ValueError("Error %d while cloning an EC point" % result)
  434. self._point = SmartPointer(self._point.get(), free_func)
  435. return self
  436. def __eq__(self, point):
  437. if not isinstance(point, EccPoint):
  438. return False
  439. cmp_func = lib_func(self, "cmp")
  440. return 0 == cmp_func(self._point.get(), point._point.get())
  441. # Only needed for Python 2
  442. def __ne__(self, point):
  443. return not self == point
  444. def __neg__(self):
  445. neg_func = lib_func(self, "neg")
  446. np = self.copy()
  447. result = neg_func(np._point.get())
  448. if result:
  449. raise ValueError("Error %d while inverting an EC point" % result)
  450. return np
  451. def copy(self):
  452. """Return a copy of this point."""
  453. x, y = self.xy
  454. np = EccPoint(x, y, self._curve_name)
  455. return np
  456. def _is_eddsa(self):
  457. return self._curve.name in ("ed25519", "ed448")
  458. def is_point_at_infinity(self):
  459. """``True`` if this is the *point-at-infinity*."""
  460. if self._is_eddsa():
  461. return self.x == 0
  462. else:
  463. return self.xy == (0, 0)
  464. def point_at_infinity(self):
  465. """Return the *point-at-infinity* for the curve."""
  466. if self._is_eddsa():
  467. return EccPoint(0, 1, self._curve_name)
  468. else:
  469. return EccPoint(0, 0, self._curve_name)
  470. @property
  471. def x(self):
  472. return self.xy[0]
  473. @property
  474. def y(self):
  475. return self.xy[1]
  476. @property
  477. def xy(self):
  478. modulus_bytes = self.size_in_bytes()
  479. xb = bytearray(modulus_bytes)
  480. yb = bytearray(modulus_bytes)
  481. get_xy = lib_func(self, "get_xy")
  482. result = get_xy(c_uint8_ptr(xb),
  483. c_uint8_ptr(yb),
  484. c_size_t(modulus_bytes),
  485. self._point.get())
  486. if result:
  487. raise ValueError("Error %d while encoding an EC point" % result)
  488. return (Integer(bytes_to_long(xb)), Integer(bytes_to_long(yb)))
  489. def size_in_bytes(self):
  490. """Size of each coordinate, in bytes."""
  491. return (self.size_in_bits() + 7) // 8
  492. def size_in_bits(self):
  493. """Size of each coordinate, in bits."""
  494. return self._curve.modulus_bits
  495. def double(self):
  496. """Double this point (in-place operation).
  497. Returns:
  498. This same object (to enable chaining).
  499. """
  500. double_func = lib_func(self, "double")
  501. result = double_func(self._point.get())
  502. if result:
  503. raise ValueError("Error %d while doubling an EC point" % result)
  504. return self
  505. def __iadd__(self, point):
  506. """Add a second point to this one"""
  507. add_func = lib_func(self, "add")
  508. result = add_func(self._point.get(), point._point.get())
  509. if result:
  510. if result == 16:
  511. raise ValueError("EC points are not on the same curve")
  512. raise ValueError("Error %d while adding two EC points" % result)
  513. return self
  514. def __add__(self, point):
  515. """Return a new point, the addition of this one and another"""
  516. np = self.copy()
  517. np += point
  518. return np
  519. def __imul__(self, scalar):
  520. """Multiply this point by a scalar"""
  521. scalar_func = lib_func(self, "scalar")
  522. if scalar < 0:
  523. raise ValueError("Scalar multiplication is only defined for non-negative integers")
  524. sb = long_to_bytes(scalar)
  525. result = scalar_func(self._point.get(),
  526. c_uint8_ptr(sb),
  527. c_size_t(len(sb)),
  528. c_ulonglong(getrandbits(64)))
  529. if result:
  530. raise ValueError("Error %d during scalar multiplication" % result)
  531. return self
  532. def __mul__(self, scalar):
  533. """Return a new point, the scalar product of this one"""
  534. np = self.copy()
  535. np *= scalar
  536. return np
  537. def __rmul__(self, left_hand):
  538. return self.__mul__(left_hand)
  539. # Last piece of initialization
  540. p192_G = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, "p192")
  541. p192 = _curves['p192']._replace(G=p192_G)
  542. _curves.update(dict.fromkeys(p192_names, p192))
  543. del p192_G, p192, p192_names
  544. p224_G = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, "p224")
  545. p224 = _curves['p224']._replace(G=p224_G)
  546. _curves.update(dict.fromkeys(p224_names, p224))
  547. del p224_G, p224, p224_names
  548. p256_G = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy, "p256")
  549. p256 = _curves['p256']._replace(G=p256_G)
  550. _curves.update(dict.fromkeys(p256_names, p256))
  551. del p256_G, p256, p256_names
  552. p384_G = EccPoint(_curves['p384'].Gx, _curves['p384'].Gy, "p384")
  553. p384 = _curves['p384']._replace(G=p384_G)
  554. _curves.update(dict.fromkeys(p384_names, p384))
  555. del p384_G, p384, p384_names
  556. p521_G = EccPoint(_curves['p521'].Gx, _curves['p521'].Gy, "p521")
  557. p521 = _curves['p521']._replace(G=p521_G)
  558. _curves.update(dict.fromkeys(p521_names, p521))
  559. del p521_G, p521, p521_names
  560. ed25519_G = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, "Ed25519")
  561. ed25519 = _curves['Ed25519']._replace(G=ed25519_G)
  562. _curves.update(dict.fromkeys(ed25519_names, ed25519))
  563. del ed25519_G, ed25519, ed25519_names
  564. ed448_G = EccPoint(_curves['Ed448'].Gx, _curves['Ed448'].Gy, "Ed448")
  565. ed448 = _curves['Ed448']._replace(G=ed448_G)
  566. _curves.update(dict.fromkeys(ed448_names, ed448))
  567. del ed448_G, ed448, ed448_names
  568. class EccKey(object):
  569. r"""Class defining an ECC key.
  570. Do not instantiate directly.
  571. Use :func:`generate`, :func:`construct` or :func:`import_key` instead.
  572. :ivar curve: The name of the curve as defined in the `ECC table`_.
  573. :vartype curve: string
  574. :ivar pointQ: an ECC point representating the public component.
  575. :vartype pointQ: :class:`EccPoint`
  576. :ivar d: A scalar that represents the private component
  577. in NIST P curves. It is smaller than the
  578. order of the generator point.
  579. :vartype d: integer
  580. :ivar seed: A seed that representats the private component
  581. in EdDSA curves
  582. (Ed25519, 32 bytes; Ed448, 57 bytes).
  583. :vartype seed: bytes
  584. """
  585. def __init__(self, **kwargs):
  586. """Create a new ECC key
  587. Keywords:
  588. curve : string
  589. The name of the curve.
  590. d : integer
  591. Mandatory for a private key one NIST P curves.
  592. It must be in the range ``[1..order-1]``.
  593. seed : bytes
  594. Mandatory for a private key on the Ed25519 (32 bytes)
  595. or Ed448 (57 bytes) curve.
  596. point : EccPoint
  597. Mandatory for a public key. If provided for a private key,
  598. the implementation will NOT check whether it matches ``d``.
  599. Only one parameter among ``d``, ``seed`` or ``point`` may be used.
  600. """
  601. kwargs_ = dict(kwargs)
  602. curve_name = kwargs_.pop("curve", None)
  603. self._d = kwargs_.pop("d", None)
  604. self._seed = kwargs_.pop("seed", None)
  605. self._point = kwargs_.pop("point", None)
  606. if curve_name is None and self._point:
  607. curve_name = self._point._curve_name
  608. if kwargs_:
  609. raise TypeError("Unknown parameters: " + str(kwargs_))
  610. if curve_name not in _curves:
  611. raise ValueError("Unsupported curve (%s)" % curve_name)
  612. self._curve = _curves[curve_name]
  613. self.curve = self._curve.desc
  614. count = int(self._d is not None) + int(self._seed is not None)
  615. if count == 0:
  616. if self._point is None:
  617. raise ValueError("At lest one between parameters 'point', 'd' or 'seed' must be specified")
  618. return
  619. if count == 2:
  620. raise ValueError("Parameters d and seed are mutually exclusive")
  621. # NIST P curves work with d, EdDSA works with seed
  622. if not self._is_eddsa():
  623. if self._seed is not None:
  624. raise ValueError("Parameter 'seed' can only be used with Ed25519 or Ed448")
  625. self._d = Integer(self._d)
  626. if not 1 <= self._d < self._curve.order:
  627. raise ValueError("Parameter d must be an integer smaller than the curve order")
  628. else:
  629. if self._d is not None:
  630. raise ValueError("Parameter d can only be used with NIST P curves")
  631. # RFC 8032, 5.1.5
  632. if self._curve.name == "ed25519":
  633. if len(self._seed) != 32:
  634. raise ValueError("Parameter seed must be 32 bytes long for Ed25519")
  635. seed_hash = SHA512.new(self._seed).digest() # h
  636. self._prefix = seed_hash[32:]
  637. tmp = bytearray(seed_hash[:32])
  638. tmp[0] &= 0xF8
  639. tmp[31] = (tmp[31] & 0x7F) | 0x40
  640. # RFC 8032, 5.2.5
  641. elif self._curve.name == "ed448":
  642. if len(self._seed) != 57:
  643. raise ValueError("Parameter seed must be 57 bytes long for Ed448")
  644. seed_hash = SHAKE256.new(self._seed).read(114) # h
  645. self._prefix = seed_hash[57:]
  646. tmp = bytearray(seed_hash[:57])
  647. tmp[0] &= 0xFC
  648. tmp[55] |= 0x80
  649. tmp[56] = 0
  650. self._d = Integer.from_bytes(tmp, byteorder='little')
  651. def _is_eddsa(self):
  652. return self._curve.desc in ("Ed25519", "Ed448")
  653. def __eq__(self, other):
  654. if not isinstance(other, EccKey):
  655. return False
  656. if other.has_private() != self.has_private():
  657. return False
  658. return other.pointQ == self.pointQ
  659. def __repr__(self):
  660. if self.has_private():
  661. if self._is_eddsa():
  662. extra = ", seed=%s" % tostr(binascii.hexlify(self._seed))
  663. else:
  664. extra = ", d=%d" % int(self._d)
  665. else:
  666. extra = ""
  667. x, y = self.pointQ.xy
  668. return "EccKey(curve='%s', point_x=%d, point_y=%d%s)" % (self._curve.desc, x, y, extra)
  669. def has_private(self):
  670. """``True`` if this key can be used for making signatures or decrypting data."""
  671. return self._d is not None
  672. # ECDSA
  673. def _sign(self, z, k):
  674. assert 0 < k < self._curve.order
  675. order = self._curve.order
  676. blind = Integer.random_range(min_inclusive=1,
  677. max_exclusive=order)
  678. blind_d = self._d * blind
  679. inv_blind_k = (blind * k).inverse(order)
  680. r = (self._curve.G * k).x % order
  681. s = inv_blind_k * (blind * z + blind_d * r) % order
  682. return (r, s)
  683. # ECDSA
  684. def _verify(self, z, rs):
  685. order = self._curve.order
  686. sinv = rs[1].inverse(order)
  687. point1 = self._curve.G * ((sinv * z) % order)
  688. point2 = self.pointQ * ((sinv * rs[0]) % order)
  689. return (point1 + point2).x == rs[0]
  690. @property
  691. def d(self):
  692. if not self.has_private():
  693. raise ValueError("This is not a private ECC key")
  694. return self._d
  695. @property
  696. def seed(self):
  697. if not self.has_private():
  698. raise ValueError("This is not a private ECC key")
  699. return self._seed
  700. @property
  701. def pointQ(self):
  702. if self._point is None:
  703. self._point = self._curve.G * self._d
  704. return self._point
  705. def public_key(self):
  706. """A matching ECC public key.
  707. Returns:
  708. a new :class:`EccKey` object
  709. """
  710. return EccKey(curve=self._curve.desc, point=self.pointQ)
  711. def _export_SEC1(self, compress):
  712. if self._is_eddsa():
  713. raise ValueError("SEC1 format is unsupported for EdDSA curves")
  714. # See 2.2 in RFC5480 and 2.3.3 in SEC1
  715. #
  716. # The first byte is:
  717. # - 0x02: compressed, only X-coordinate, Y-coordinate is even
  718. # - 0x03: compressed, only X-coordinate, Y-coordinate is odd
  719. # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate
  720. #
  721. # PAI is in theory encoded as 0x00.
  722. modulus_bytes = self.pointQ.size_in_bytes()
  723. if compress:
  724. if self.pointQ.y.is_odd():
  725. first_byte = b'\x03'
  726. else:
  727. first_byte = b'\x02'
  728. public_key = (first_byte +
  729. self.pointQ.x.to_bytes(modulus_bytes))
  730. else:
  731. public_key = (b'\x04' +
  732. self.pointQ.x.to_bytes(modulus_bytes) +
  733. self.pointQ.y.to_bytes(modulus_bytes))
  734. return public_key
  735. def _export_eddsa(self):
  736. x, y = self.pointQ.xy
  737. if self._curve.name == "ed25519":
  738. result = bytearray(y.to_bytes(32, byteorder='little'))
  739. result[31] = ((x & 1) << 7) | result[31]
  740. elif self._curve.name == "ed448":
  741. result = bytearray(y.to_bytes(57, byteorder='little'))
  742. result[56] = (x & 1) << 7
  743. else:
  744. raise ValueError("Not an EdDSA key to export")
  745. return bytes(result)
  746. def _export_subjectPublicKeyInfo(self, compress):
  747. if self._is_eddsa():
  748. oid = self._curve.oid
  749. public_key = self._export_eddsa()
  750. params = None
  751. else:
  752. oid = "1.2.840.10045.2.1" # unrestricted
  753. public_key = self._export_SEC1(compress)
  754. params = DerObjectId(self._curve.oid)
  755. return _create_subject_public_key_info(oid,
  756. public_key,
  757. params)
  758. def _export_rfc5915_private_der(self, include_ec_params=True):
  759. assert self.has_private()
  760. # ECPrivateKey ::= SEQUENCE {
  761. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  762. # privateKey OCTET STRING,
  763. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  764. # publicKey [1] BIT STRING OPTIONAL
  765. # }
  766. # Public key - uncompressed form
  767. modulus_bytes = self.pointQ.size_in_bytes()
  768. public_key = (b'\x04' +
  769. self.pointQ.x.to_bytes(modulus_bytes) +
  770. self.pointQ.y.to_bytes(modulus_bytes))
  771. seq = [1,
  772. DerOctetString(self.d.to_bytes(modulus_bytes)),
  773. DerObjectId(self._curve.oid, explicit=0),
  774. DerBitString(public_key, explicit=1)]
  775. if not include_ec_params:
  776. del seq[2]
  777. return DerSequence(seq).encode()
  778. def _export_pkcs8(self, **kwargs):
  779. from Crypto.IO import PKCS8
  780. if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs:
  781. raise ValueError("At least the 'protection' parameter must be present")
  782. if self._is_eddsa():
  783. oid = self._curve.oid
  784. private_key = DerOctetString(self._seed).encode()
  785. params = None
  786. else:
  787. oid = "1.2.840.10045.2.1" # unrestricted
  788. private_key = self._export_rfc5915_private_der(include_ec_params=False)
  789. params = DerObjectId(self._curve.oid)
  790. result = PKCS8.wrap(private_key,
  791. oid,
  792. key_params=params,
  793. **kwargs)
  794. return result
  795. def _export_public_pem(self, compress):
  796. from Crypto.IO import PEM
  797. encoded_der = self._export_subjectPublicKeyInfo(compress)
  798. return PEM.encode(encoded_der, "PUBLIC KEY")
  799. def _export_private_pem(self, passphrase, **kwargs):
  800. from Crypto.IO import PEM
  801. encoded_der = self._export_rfc5915_private_der()
  802. return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs)
  803. def _export_private_clear_pkcs8_in_clear_pem(self):
  804. from Crypto.IO import PEM
  805. encoded_der = self._export_pkcs8()
  806. return PEM.encode(encoded_der, "PRIVATE KEY")
  807. def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs):
  808. from Crypto.IO import PEM
  809. assert passphrase
  810. if 'protection' not in kwargs:
  811. raise ValueError("At least the 'protection' parameter should be present")
  812. encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs)
  813. return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY")
  814. def _export_openssh(self, compress):
  815. if self.has_private():
  816. raise ValueError("Cannot export OpenSSH private keys")
  817. desc = self._curve.openssh
  818. if desc is None:
  819. raise ValueError("Cannot export %s keys as OpenSSH" % self._curve.name)
  820. elif desc == "ssh-ed25519":
  821. public_key = self._export_eddsa()
  822. comps = (tobytes(desc), tobytes(public_key))
  823. else:
  824. modulus_bytes = self.pointQ.size_in_bytes()
  825. if compress:
  826. first_byte = 2 + self.pointQ.y.is_odd()
  827. public_key = (bchr(first_byte) +
  828. self.pointQ.x.to_bytes(modulus_bytes))
  829. else:
  830. public_key = (b'\x04' +
  831. self.pointQ.x.to_bytes(modulus_bytes) +
  832. self.pointQ.y.to_bytes(modulus_bytes))
  833. middle = desc.split("-")[2]
  834. comps = (tobytes(desc), tobytes(middle), public_key)
  835. blob = b"".join([struct.pack(">I", len(x)) + x for x in comps])
  836. return desc + " " + tostr(binascii.b2a_base64(blob))
  837. def export_key(self, **kwargs):
  838. """Export this ECC key.
  839. Args:
  840. format (string):
  841. The output format:
  842. - ``'DER'``. The key will be encoded in ASN.1 DER format (binary).
  843. For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure
  844. defined in `RFC5480`_ will be used.
  845. For a private key, the ASN.1 ``ECPrivateKey`` structure defined
  846. in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope,
  847. see the ``use_pkcs8`` flag below).
  848. - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII).
  849. - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format
  850. (ASCII, public keys only).
  851. - ``'SEC1'``. The public key (i.e., the EC point) will be encoded
  852. into ``bytes`` according to Section 2.3.3 of `SEC1`_
  853. (which is a subset of the older X9.62 ITU standard).
  854. Only for NIST P-curves.
  855. - ``'raw'``. The public key will be encoded as ``bytes``,
  856. without any metadata.
  857. * For NIST P-curves: equivalent to ``'SEC1'``.
  858. * For EdDSA curves: ``bytes`` in the format defined in `RFC8032`_.
  859. passphrase (bytes or string):
  860. (*Private keys only*) The passphrase to protect the
  861. private key.
  862. use_pkcs8 (boolean):
  863. (*Private keys only*)
  864. If ``True`` (default and recommended), the `PKCS#8`_ representation
  865. will be used. It must be ``True`` for EdDSA curves.
  866. If ``False`` and a passphrase is present, the obsolete PEM
  867. encryption will be used.
  868. protection (string):
  869. When a private key is exported with password-protection
  870. and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be
  871. present,
  872. For all possible protection schemes,
  873. refer to :ref:`the encryption parameters of PKCS#8<enc_params>`.
  874. It is recommended to use ``'PBKDF2WithHMAC-SHA5126AndAES128-CBC'``.
  875. compress (boolean):
  876. If ``True``, the method returns a more compact representation
  877. of the public key, with the X-coordinate only.
  878. If ``False`` (default), the method returns the full public key.
  879. This parameter is ignored for EdDSA curves, as compression is
  880. mandatory.
  881. prot_params (dict):
  882. When a private key is exported with password-protection
  883. and PKCS#8 (both ``DER`` and ``PEM`` formats), this dictionary
  884. contains the parameters to use to derive the encryption key
  885. from the passphrase.
  886. For all possible values,
  887. refer to :ref:`the encryption parameters of PKCS#8<enc_params>`.
  888. The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2,
  889. and ``{'iteration_count':131072}`` for scrypt.
  890. .. warning::
  891. If you don't provide a passphrase, the private key will be
  892. exported in the clear!
  893. .. note::
  894. When exporting a private key with password-protection and `PKCS#8`_
  895. (both ``DER`` and ``PEM`` formats), any extra parameters
  896. to ``export_key()`` will be passed to :mod:`Crypto.IO.PKCS8`.
  897. .. _PEM: http://www.ietf.org/rfc/rfc1421.txt
  898. .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt
  899. .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt
  900. .. _RFC5480: https://tools.ietf.org/html/rfc5480
  901. .. _SEC1: https://www.secg.org/sec1-v2.pdf
  902. Returns:
  903. A multi-line string (for ``'PEM'`` and ``'OpenSSH'``) or
  904. ``bytes`` (for ``'DER'``, ``'SEC1'``, and ``'raw'``) with the encoded key.
  905. """
  906. args = kwargs.copy()
  907. ext_format = args.pop("format")
  908. if ext_format not in ("PEM", "DER", "OpenSSH", "SEC1", "raw"):
  909. raise ValueError("Unknown format '%s'" % ext_format)
  910. compress = args.pop("compress", False)
  911. if self.has_private():
  912. passphrase = args.pop("passphrase", None)
  913. if is_string(passphrase):
  914. passphrase = tobytes(passphrase)
  915. if not passphrase:
  916. raise ValueError("Empty passphrase")
  917. use_pkcs8 = args.pop("use_pkcs8", True)
  918. if not use_pkcs8:
  919. if self._is_eddsa():
  920. raise ValueError("'pkcs8' must be True for EdDSA curves")
  921. if 'protection' in args:
  922. raise ValueError("'protection' is only supported for PKCS#8")
  923. if ext_format == "PEM":
  924. if use_pkcs8:
  925. if passphrase:
  926. return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args)
  927. else:
  928. return self._export_private_clear_pkcs8_in_clear_pem()
  929. else:
  930. return self._export_private_pem(passphrase, **args)
  931. elif ext_format == "DER":
  932. # DER
  933. if passphrase and not use_pkcs8:
  934. raise ValueError("Private keys can only be encrpyted with DER using PKCS#8")
  935. if use_pkcs8:
  936. return self._export_pkcs8(passphrase=passphrase, **args)
  937. else:
  938. return self._export_rfc5915_private_der()
  939. else:
  940. raise ValueError("Private keys cannot be exported "
  941. "in the '%s' format" % ext_format)
  942. else: # Public key
  943. if args:
  944. raise ValueError("Unexpected parameters: '%s'" % args)
  945. if ext_format == "PEM":
  946. return self._export_public_pem(compress)
  947. elif ext_format == "DER":
  948. return self._export_subjectPublicKeyInfo(compress)
  949. elif ext_format == "SEC1":
  950. return self._export_SEC1(compress)
  951. elif ext_format == "raw":
  952. if self._curve.name in ('ed25519', 'ed448'):
  953. return self._export_eddsa()
  954. else:
  955. return self._export_SEC1(compress)
  956. else:
  957. return self._export_openssh(compress)
  958. def generate(**kwargs):
  959. """Generate a new private key on the given curve.
  960. Args:
  961. curve (string):
  962. Mandatory. It must be a curve name defined in the `ECC table`_.
  963. randfunc (callable):
  964. Optional. The RNG to read randomness from.
  965. If ``None``, :func:`Crypto.Random.get_random_bytes` is used.
  966. """
  967. curve_name = kwargs.pop("curve")
  968. curve = _curves[curve_name]
  969. randfunc = kwargs.pop("randfunc", get_random_bytes)
  970. if kwargs:
  971. raise TypeError("Unknown parameters: " + str(kwargs))
  972. if _curves[curve_name].name == "ed25519":
  973. seed = randfunc(32)
  974. new_key = EccKey(curve=curve_name, seed=seed)
  975. elif _curves[curve_name].name == "ed448":
  976. seed = randfunc(57)
  977. new_key = EccKey(curve=curve_name, seed=seed)
  978. else:
  979. d = Integer.random_range(min_inclusive=1,
  980. max_exclusive=curve.order,
  981. randfunc=randfunc)
  982. new_key = EccKey(curve=curve_name, d=d)
  983. return new_key
  984. def construct(**kwargs):
  985. """Build a new ECC key (private or public) starting
  986. from some base components.
  987. In most cases, you will already have an existing key
  988. which you can read in with :func:`import_key` instead
  989. of this function.
  990. Args:
  991. curve (string):
  992. Mandatory. The name of the elliptic curve, as defined in the `ECC table`_.
  993. d (integer):
  994. Mandatory for a private key and a NIST P-curve (e.g., P-256):
  995. the integer in the range ``[1..order-1]`` that represents the key.
  996. seed (bytes):
  997. Mandatory for a private key and an EdDSA curve.
  998. It must be 32 bytes for Ed25519, and 57 bytes for Ed448.
  999. point_x (integer):
  1000. Mandatory for a public key: the X coordinate (affine) of the ECC point.
  1001. point_y (integer):
  1002. Mandatory for a public key: the Y coordinate (affine) of the ECC point.
  1003. Returns:
  1004. :class:`EccKey` : a new ECC key object
  1005. """
  1006. curve_name = kwargs["curve"]
  1007. curve = _curves[curve_name]
  1008. point_x = kwargs.pop("point_x", None)
  1009. point_y = kwargs.pop("point_y", None)
  1010. if "point" in kwargs:
  1011. raise TypeError("Unknown keyword: point")
  1012. if None not in (point_x, point_y):
  1013. # ValueError is raised if the point is not on the curve
  1014. kwargs["point"] = EccPoint(point_x, point_y, curve_name)
  1015. new_key = EccKey(**kwargs)
  1016. # Validate that the private key matches the public one
  1017. # because EccKey will not do that automatically
  1018. if new_key.has_private() and 'point' in kwargs:
  1019. pub_key = curve.G * new_key.d
  1020. if pub_key.xy != (point_x, point_y):
  1021. raise ValueError("Private and public ECC keys do not match")
  1022. return new_key
  1023. def _import_public_der(ec_point, curve_oid=None, curve_name=None):
  1024. """Convert an encoded EC point into an EccKey object
  1025. ec_point: byte string with the EC point (SEC1-encoded)
  1026. curve_oid: string with the name the curve
  1027. curve_name: string with the OID of the curve
  1028. Either curve_id or curve_name must be specified
  1029. """
  1030. for _curve_name, curve in _curves.items():
  1031. if curve_oid and curve.oid == curve_oid:
  1032. break
  1033. if curve_name == _curve_name:
  1034. break
  1035. else:
  1036. if curve_oid:
  1037. raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid)
  1038. else:
  1039. raise UnsupportedEccFeature("Unsupported ECC curve (%s)" % curve_name)
  1040. # See 2.2 in RFC5480 and 2.3.3 in SEC1
  1041. # The first byte is:
  1042. # - 0x02: compressed, only X-coordinate, Y-coordinate is even
  1043. # - 0x03: compressed, only X-coordinate, Y-coordinate is odd
  1044. # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate
  1045. #
  1046. # PAI is in theory encoded as 0x00.
  1047. modulus_bytes = curve.p.size_in_bytes()
  1048. point_type = bord(ec_point[0])
  1049. # Uncompressed point
  1050. if point_type == 0x04:
  1051. if len(ec_point) != (1 + 2 * modulus_bytes):
  1052. raise ValueError("Incorrect EC point length")
  1053. x = Integer.from_bytes(ec_point[1:modulus_bytes+1])
  1054. y = Integer.from_bytes(ec_point[modulus_bytes+1:])
  1055. # Compressed point
  1056. elif point_type in (0x02, 0x03):
  1057. if len(ec_point) != (1 + modulus_bytes):
  1058. raise ValueError("Incorrect EC point length")
  1059. x = Integer.from_bytes(ec_point[1:])
  1060. # Right now, we only support Short Weierstrass curves
  1061. y = (x**3 - x*3 + curve.b).sqrt(curve.p)
  1062. if point_type == 0x02 and y.is_odd():
  1063. y = curve.p - y
  1064. if point_type == 0x03 and y.is_even():
  1065. y = curve.p - y
  1066. else:
  1067. raise ValueError("Incorrect EC point encoding")
  1068. return construct(curve=_curve_name, point_x=x, point_y=y)
  1069. def _import_subjectPublicKeyInfo(encoded, *kwargs):
  1070. """Convert a subjectPublicKeyInfo into an EccKey object"""
  1071. # See RFC5480
  1072. # Parse the generic subjectPublicKeyInfo structure
  1073. oid, ec_point, params = _expand_subject_public_key_info(encoded)
  1074. nist_p_oids = (
  1075. "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted)
  1076. "1.3.132.1.12", # id-ecDH
  1077. "1.3.132.1.13" # id-ecMQV
  1078. )
  1079. eddsa_oids = {
  1080. "1.3.101.112": ("Ed25519", _import_ed25519_public_key), # id-Ed25519
  1081. "1.3.101.113": ("Ed448", _import_ed448_public_key) # id-Ed448
  1082. }
  1083. if oid in nist_p_oids:
  1084. # See RFC5480
  1085. # Parameters are mandatory and encoded as ECParameters
  1086. # ECParameters ::= CHOICE {
  1087. # namedCurve OBJECT IDENTIFIER
  1088. # -- implicitCurve NULL
  1089. # -- specifiedCurve SpecifiedECDomain
  1090. # }
  1091. # implicitCurve and specifiedCurve are not supported (as per RFC)
  1092. if not params:
  1093. raise ValueError("Missing ECC parameters for ECC OID %s" % oid)
  1094. try:
  1095. curve_oid = DerObjectId().decode(params).value
  1096. except ValueError:
  1097. raise ValueError("Error decoding namedCurve")
  1098. # ECPoint ::= OCTET STRING
  1099. return _import_public_der(ec_point, curve_oid=curve_oid)
  1100. elif oid in eddsa_oids:
  1101. # See RFC8410
  1102. curve_name, import_eddsa_public_key = eddsa_oids[oid]
  1103. # Parameters must be absent
  1104. if params:
  1105. raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid)
  1106. x, y = import_eddsa_public_key(ec_point)
  1107. return construct(point_x=x, point_y=y, curve=curve_name)
  1108. else:
  1109. raise UnsupportedEccFeature("Unsupported ECC OID: %s" % oid)
  1110. def _import_rfc5915_der(encoded, passphrase, curve_oid=None):
  1111. # See RFC5915 https://tools.ietf.org/html/rfc5915
  1112. #
  1113. # ECPrivateKey ::= SEQUENCE {
  1114. # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  1115. # privateKey OCTET STRING,
  1116. # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
  1117. # publicKey [1] BIT STRING OPTIONAL
  1118. # }
  1119. private_key = DerSequence().decode(encoded, nr_elements=(3, 4))
  1120. if private_key[0] != 1:
  1121. raise ValueError("Incorrect ECC private key version")
  1122. try:
  1123. parameters = DerObjectId(explicit=0).decode(private_key[2]).value
  1124. if curve_oid is not None and parameters != curve_oid:
  1125. raise ValueError("Curve mismatch")
  1126. curve_oid = parameters
  1127. except ValueError:
  1128. pass
  1129. if curve_oid is None:
  1130. raise ValueError("No curve found")
  1131. for curve_name, curve in _curves.items():
  1132. if curve.oid == curve_oid:
  1133. break
  1134. else:
  1135. raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid)
  1136. scalar_bytes = DerOctetString().decode(private_key[1]).payload
  1137. modulus_bytes = curve.p.size_in_bytes()
  1138. if len(scalar_bytes) != modulus_bytes:
  1139. raise ValueError("Private key is too small")
  1140. d = Integer.from_bytes(scalar_bytes)
  1141. # Decode public key (if any)
  1142. if len(private_key) > 2:
  1143. public_key_enc = DerBitString(explicit=1).decode(private_key[-1]).value
  1144. public_key = _import_public_der(public_key_enc, curve_oid=curve_oid)
  1145. point_x = public_key.pointQ.x
  1146. point_y = public_key.pointQ.y
  1147. else:
  1148. point_x = point_y = None
  1149. return construct(curve=curve_name, d=d, point_x=point_x, point_y=point_y)
  1150. def _import_pkcs8(encoded, passphrase):
  1151. from Crypto.IO import PKCS8
  1152. algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase)
  1153. nist_p_oids = (
  1154. "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted)
  1155. "1.3.132.1.12", # id-ecDH
  1156. "1.3.132.1.13" # id-ecMQV
  1157. )
  1158. eddsa_oids = {
  1159. "1.3.101.112": "Ed25519", # id-Ed25519
  1160. "1.3.101.113": "Ed448", # id-Ed448
  1161. }
  1162. if algo_oid in nist_p_oids:
  1163. curve_oid = DerObjectId().decode(params).value
  1164. return _import_rfc5915_der(private_key, passphrase, curve_oid)
  1165. elif algo_oid in eddsa_oids:
  1166. if params is not None:
  1167. raise ValueError("EdDSA ECC private key must not have parameters")
  1168. curve_oid = None
  1169. seed = DerOctetString().decode(private_key).payload
  1170. return construct(curve=eddsa_oids[algo_oid], seed=seed)
  1171. else:
  1172. raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid)
  1173. def _import_x509_cert(encoded, *kwargs):
  1174. sp_info = _extract_subject_public_key_info(encoded)
  1175. return _import_subjectPublicKeyInfo(sp_info)
  1176. def _import_der(encoded, passphrase):
  1177. try:
  1178. return _import_subjectPublicKeyInfo(encoded, passphrase)
  1179. except UnsupportedEccFeature as err:
  1180. raise err
  1181. except (ValueError, TypeError, IndexError):
  1182. pass
  1183. try:
  1184. return _import_x509_cert(encoded, passphrase)
  1185. except UnsupportedEccFeature as err:
  1186. raise err
  1187. except (ValueError, TypeError, IndexError):
  1188. pass
  1189. try:
  1190. return _import_rfc5915_der(encoded, passphrase)
  1191. except UnsupportedEccFeature as err:
  1192. raise err
  1193. except (ValueError, TypeError, IndexError):
  1194. pass
  1195. try:
  1196. return _import_pkcs8(encoded, passphrase)
  1197. except UnsupportedEccFeature as err:
  1198. raise err
  1199. except (ValueError, TypeError, IndexError):
  1200. pass
  1201. raise ValueError("Not an ECC DER key")
  1202. def _import_openssh_public(encoded):
  1203. parts = encoded.split(b' ')
  1204. if len(parts) not in (2, 3):
  1205. raise ValueError("Not an openssh public key")
  1206. try:
  1207. keystring = binascii.a2b_base64(parts[1])
  1208. keyparts = []
  1209. while len(keystring) > 4:
  1210. lk = struct.unpack(">I", keystring[:4])[0]
  1211. keyparts.append(keystring[4:4 + lk])
  1212. keystring = keystring[4 + lk:]
  1213. if parts[0] != keyparts[0]:
  1214. raise ValueError("Mismatch in openssh public key")
  1215. # NIST P curves
  1216. if parts[0].startswith(b"ecdsa-sha2-"):
  1217. for curve_name, curve in _curves.items():
  1218. if curve.openssh is None:
  1219. continue
  1220. if not curve.openssh.startswith("ecdsa-sha2"):
  1221. continue
  1222. middle = tobytes(curve.openssh.split("-")[2])
  1223. if keyparts[1] == middle:
  1224. break
  1225. else:
  1226. raise ValueError("Unsupported ECC curve: " + middle)
  1227. ecc_key = _import_public_der(keyparts[2], curve_oid=curve.oid)
  1228. # EdDSA
  1229. elif parts[0] == b"ssh-ed25519":
  1230. x, y = _import_ed25519_public_key(keyparts[1])
  1231. ecc_key = construct(curve="Ed25519", point_x=x, point_y=y)
  1232. else:
  1233. raise ValueError("Unsupported SSH key type: " + parts[0])
  1234. except (IndexError, TypeError, binascii.Error):
  1235. raise ValueError("Error parsing SSH key type: " + parts[0])
  1236. return ecc_key
  1237. def _import_openssh_private_ecc(data, password):
  1238. from ._openssh import (import_openssh_private_generic,
  1239. read_bytes, read_string, check_padding)
  1240. key_type, decrypted = import_openssh_private_generic(data, password)
  1241. eddsa_keys = {
  1242. "ssh-ed25519": ("Ed25519", _import_ed25519_public_key, 32),
  1243. }
  1244. # https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04
  1245. if key_type.startswith("ecdsa-sha2"):
  1246. ecdsa_curve_name, decrypted = read_string(decrypted)
  1247. if ecdsa_curve_name not in _curves:
  1248. raise UnsupportedEccFeature("Unsupported ECC curve %s" % ecdsa_curve_name)
  1249. curve = _curves[ecdsa_curve_name]
  1250. modulus_bytes = (curve.modulus_bits + 7) // 8
  1251. public_key, decrypted = read_bytes(decrypted)
  1252. if bord(public_key[0]) != 4:
  1253. raise ValueError("Only uncompressed OpenSSH EC keys are supported")
  1254. if len(public_key) != 2 * modulus_bytes + 1:
  1255. raise ValueError("Incorrect public key length")
  1256. point_x = Integer.from_bytes(public_key[1:1+modulus_bytes])
  1257. point_y = Integer.from_bytes(public_key[1+modulus_bytes:])
  1258. private_key, decrypted = read_bytes(decrypted)
  1259. d = Integer.from_bytes(private_key)
  1260. params = {'d': d, 'curve': ecdsa_curve_name}
  1261. elif key_type in eddsa_keys:
  1262. curve_name, import_eddsa_public_key, seed_len = eddsa_keys[key_type]
  1263. public_key, decrypted = read_bytes(decrypted)
  1264. point_x, point_y = import_eddsa_public_key(public_key)
  1265. private_public_key, decrypted = read_bytes(decrypted)
  1266. seed = private_public_key[:seed_len]
  1267. params = {'seed': seed, 'curve': curve_name}
  1268. else:
  1269. raise ValueError("Unsupport SSH agent key type:" + key_type)
  1270. _, padded = read_string(decrypted) # Comment
  1271. check_padding(padded)
  1272. return construct(point_x=point_x, point_y=point_y, **params)
  1273. def _import_ed25519_public_key(encoded):
  1274. """Import an Ed25519 ECC public key, encoded as raw bytes as described
  1275. in RFC8032_.
  1276. Args:
  1277. encoded (bytes):
  1278. The Ed25519 public key to import. It must be 32 bytes long.
  1279. Returns:
  1280. :class:`EccKey` : a new ECC key object
  1281. Raises:
  1282. ValueError: when the given key cannot be parsed.
  1283. .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032
  1284. """
  1285. if len(encoded) != 32:
  1286. raise ValueError("Incorrect length. Only Ed25519 public keys are supported.")
  1287. p = Integer(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed) # 2**255 - 19
  1288. d = 37095705934669439343138083508754565189542113879843219016388785533085940283555
  1289. y = bytearray(encoded)
  1290. x_lsb = y[31] >> 7
  1291. y[31] &= 0x7F
  1292. point_y = Integer.from_bytes(y, byteorder='little')
  1293. if point_y >= p:
  1294. raise ValueError("Invalid Ed25519 key (y)")
  1295. if point_y == 1:
  1296. return 0, 1
  1297. u = (point_y**2 - 1) % p
  1298. v = ((point_y**2 % p) * d + 1) % p
  1299. try:
  1300. v_inv = v.inverse(p)
  1301. x2 = (u * v_inv) % p
  1302. point_x = Integer._tonelli_shanks(x2, p)
  1303. if (point_x & 1) != x_lsb:
  1304. point_x = p - point_x
  1305. except ValueError:
  1306. raise ValueError("Invalid Ed25519 public key")
  1307. return point_x, point_y
  1308. def _import_ed448_public_key(encoded):
  1309. """Import an Ed448 ECC public key, encoded as raw bytes as described
  1310. in RFC8032_.
  1311. Args:
  1312. encoded (bytes):
  1313. The Ed448 public key to import. It must be 57 bytes long.
  1314. Returns:
  1315. :class:`EccKey` : a new ECC key object
  1316. Raises:
  1317. ValueError: when the given key cannot be parsed.
  1318. .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032
  1319. """
  1320. if len(encoded) != 57:
  1321. raise ValueError("Incorrect length. Only Ed448 public keys are supported.")
  1322. p = Integer(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff) # 2**448 - 2**224 - 1
  1323. d = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756
  1324. y = encoded[:56]
  1325. x_lsb = bord(encoded[56]) >> 7
  1326. point_y = Integer.from_bytes(y, byteorder='little')
  1327. if point_y >= p:
  1328. raise ValueError("Invalid Ed448 key (y)")
  1329. if point_y == 1:
  1330. return 0, 1
  1331. u = (point_y**2 - 1) % p
  1332. v = ((point_y**2 % p) * d - 1) % p
  1333. try:
  1334. v_inv = v.inverse(p)
  1335. x2 = (u * v_inv) % p
  1336. point_x = Integer._tonelli_shanks(x2, p)
  1337. if (point_x & 1) != x_lsb:
  1338. point_x = p - point_x
  1339. except ValueError:
  1340. raise ValueError("Invalid Ed448 public key")
  1341. return point_x, point_y
  1342. def import_key(encoded, passphrase=None, curve_name=None):
  1343. """Import an ECC key (public or private).
  1344. Args:
  1345. encoded (bytes or multi-line string):
  1346. The ECC key to import.
  1347. The function will try to automatically detect the right format.
  1348. Supported formats for an ECC **public** key:
  1349. * X.509 certificate: binary (DER) or ASCII (PEM).
  1350. * X.509 ``subjectPublicKeyInfo``: binary (DER) or ASCII (PEM).
  1351. * SEC1_ (or X9.62), as ``bytes``. NIST P curves only.
  1352. You must also provide the ``curve_name`` (with a value from the `ECC table`_)
  1353. * OpenSSH line, defined in RFC5656_ and RFC8709_ (ASCII).
  1354. This is normally the content of files like ``~/.ssh/id_ecdsa.pub``.
  1355. Supported formats for an ECC **private** key:
  1356. * A binary ``ECPrivateKey`` structure, as defined in `RFC5915`_ (DER).
  1357. NIST P curves only.
  1358. * A `PKCS#8`_ structure (or the more recent Asymmetric Key Package, RFC5958_): binary (DER) or ASCII (PEM).
  1359. * `OpenSSH 6.5`_ and newer versions (ASCII).
  1360. Private keys can be in the clear or password-protected.
  1361. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
  1362. passphrase (byte string):
  1363. The passphrase to use for decrypting a private key.
  1364. Encryption may be applied protected at the PEM level (not recommended)
  1365. or at the PKCS#8 level (recommended).
  1366. This parameter is ignored if the key in input is not encrypted.
  1367. curve_name (string):
  1368. For a SEC1 encoding only. This is the name of the curve,
  1369. as defined in the `ECC table`_.
  1370. .. note::
  1371. To import EdDSA private and public keys, when encoded as raw ``bytes``, use:
  1372. * :func:`Crypto.Signature.eddsa.import_public_key`, or
  1373. * :func:`Crypto.Signature.eddsa.import_private_key`.
  1374. Returns:
  1375. :class:`EccKey` : a new ECC key object
  1376. Raises:
  1377. ValueError: when the given key cannot be parsed (possibly because
  1378. the pass phrase is wrong).
  1379. .. _RFC1421: https://datatracker.ietf.org/doc/html/rfc1421
  1380. .. _RFC1423: https://datatracker.ietf.org/doc/html/rfc1423
  1381. .. _RFC5915: https://datatracker.ietf.org/doc/html/rfc5915
  1382. .. _RFC5656: https://datatracker.ietf.org/doc/html/rfc5656
  1383. .. _RFC8709: https://datatracker.ietf.org/doc/html/rfc8709
  1384. .. _RFC5958: https://datatracker.ietf.org/doc/html/rfc5958
  1385. .. _`PKCS#8`: https://datatracker.ietf.org/doc/html/rfc5208
  1386. .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf
  1387. .. _SEC1: https://www.secg.org/sec1-v2.pdf
  1388. """
  1389. from Crypto.IO import PEM
  1390. encoded = tobytes(encoded)
  1391. if passphrase is not None:
  1392. passphrase = tobytes(passphrase)
  1393. # PEM
  1394. if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'):
  1395. text_encoded = tostr(encoded)
  1396. openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase)
  1397. result = _import_openssh_private_ecc(openssh_encoded, passphrase)
  1398. return result
  1399. elif encoded.startswith(b'-----'):
  1400. text_encoded = tostr(encoded)
  1401. # Remove any EC PARAMETERS section
  1402. # Ignore its content because the curve type must be already given in the key
  1403. ecparams_start = "-----BEGIN EC PARAMETERS-----"
  1404. ecparams_end = "-----END EC PARAMETERS-----"
  1405. text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "",
  1406. text_encoded,
  1407. flags=re.DOTALL)
  1408. der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase)
  1409. if enc_flag:
  1410. passphrase = None
  1411. try:
  1412. result = _import_der(der_encoded, passphrase)
  1413. except UnsupportedEccFeature as uef:
  1414. raise uef
  1415. except ValueError:
  1416. raise ValueError("Invalid DER encoding inside the PEM file")
  1417. return result
  1418. # OpenSSH
  1419. if encoded.startswith((b'ecdsa-sha2-', b'ssh-ed25519')):
  1420. return _import_openssh_public(encoded)
  1421. # DER
  1422. if len(encoded) > 0 and bord(encoded[0]) == 0x30:
  1423. return _import_der(encoded, passphrase)
  1424. # SEC1
  1425. if len(encoded) > 0 and bord(encoded[0]) in (0x02, 0x03, 0x04):
  1426. if curve_name is None:
  1427. raise ValueError("No curve name was provided")
  1428. return _import_public_der(encoded, curve_name=curve_name)
  1429. raise ValueError("ECC key format is not supported")
  1430. if __name__ == "__main__":
  1431. import time
  1432. d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd
  1433. point = _curves['p256'].G.copy()
  1434. count = 3000
  1435. start = time.time()
  1436. for x in range(count):
  1437. pointX = point * d
  1438. print("(P-256 G)", (time.time() - start) / count * 1000, "ms")
  1439. start = time.time()
  1440. for x in range(count):
  1441. pointX = pointX * d
  1442. print("(P-256 arbitrary point)", (time.time() - start) / count * 1000, "ms")