ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ." ¤‡ú*õ'VŽ|¼´Úgllº¼klz[Æüï÷Aób‡Eÿ dÑ»Xx9ÃÜ£ÁT/`¼¸vI±Ýµ·Ë‚“G³þ*Ÿû´r|*}<¨îºœ @¦mÄ’M¹”.œ«Y–|6ÏU¤jç¥ÕÞqO ˜kDÆÁ¨5ÿ š;ÐЦ¦€GÙk \ –Þ=â¼=SͧµªS°ÚÍpÜãQűÀõ¬?ÃÁ1Ñ•õZà?hóœ€ L¦l{Y*K˜Ù›zc˜–ˆâ ø+¾ ­-Ök¥%ùEÜA'}ˆ><ÊIè“bpÍ/qÞâvoX€w,\úªò6Z[XdÒæ­@Ö—€$òJí#é>'°Ú ôª˜<)4ryÙ£|óAÅn5žêŸyÒäMÝ2{"}‰–¤l÷ûWX\l¾Á¸góÉOÔ /óñB¤f¸çñ[.P˜ZsÊË*ßT܈§QN¢’¡¨§V¼(Üù*eÕ“”5T¨‹Âê¥FŒã½Dü[8'Ò¥a…Ú¶k7a *•›¼'Ò·\8¨ª\@\õ¢¦íq+DÙrmÎ…_ªæ»ŠÓœ¡¯’Ré9MÅ×D™lælffc+ŒÑ,ý™ÿ ¯þǤ=Å’Á7µ÷ÚÛ/“Ü€ñýã¼àí¾ÕÑ+ƒ,uµMâÀÄbm:ÒÎPæ{˜Gz[ƒ¯«® KHà`ߨŠéí¯P8Aq.C‰ à€kòpj´kN¶qô€…Õ,ÜNŠª-­{Zö’æû44‰sŽè‰îVíRœÕm" 6?³D9¡ÇTíÅꋇ`4«¸ÝÁô ï’ýorqКÇZ«x4Žâéþuïf¹µö[P ,Q£éaX±`PÉÍZ ¸äYúg üAx ’6Lê‚xÝÓ*äQ  Ï’¨hÍ =²,6ï#rÃ<¯–£»ƒ‹,–ê•€ aÛsñ'%Æ"®ÛüìBᝠHÚ3ß°©$“XnœÖ’î2ËTeûìxîß ¦å¿çÉ ðK§þ{‘t‚Ϋ¬jéîZ[ ”š7L¥4VÚCE×]m¤Øy”ä4-dz£œ§¸x.*ãÊÊ b÷•h:©‡¦s`BTÁRû¾g⻩‹jø sF¢àJøFl‘È•Xᓁà~*j¯ +(ÚÕ6-£¯÷GŠØy‚<Ç’.F‹Hœw(+)ÜÜâÈzÄäT§FߘãÏ;DmVœ3Àu@mÚüXÝü•3B¨òÌÁÛ<·ÃÜ z,Ì@õÅ·d2]ü8s÷IôÞ¯^Ç9¢u„~ëAŸï4«M? K]­ÅàPl@s_ p:°¬ZR”´›JC[CS.h‹ƒïËœ«Æ]–÷ó‚wR×k7X‰k›‘´ù¦=¡«‰¨¨Â')—71ó’c‡Ðúµ `é.{§p¹ój\Ž{1h{o±Ý=áUÊïGÖŒõ–-BÄm+AZX¶¡ ïHðæ¥JmÙ;…䡟ˆ¦ ° äšiÉg«$üMk5¤L“’çÊvïâï ,=f“"íἊ5ô¬x6{ɏžID0e¸vçmi'︧ºð9$ò¹÷*£’9ÿ ²TÔ…×>JV¥}Œ}$p[bÔ®*[jzS*8 ”·T›Í–ñUîƒwo$áè=LT™ç—~ô·¤ÈÚ$榍q‰„+´kFm)ž‹©i–ËqÞŠ‰à¶ü( ‚•§ •°ò·‡#5ª•µÊ﯅¡X¨šÁ*F#TXJÊ ušJVÍ&=iÄs1‚3•'fý§5Ñ<=[íÞ­ PÚ;ѱÌ_~Ä££8rÞ ²w;’hDT°>ÈG¬8Á²ÚzŽ®ò®qZcqJêäÞ-ö[ܘbň±çb“ж31²n×iƒðÕ;1¶þÉ ªX‰,ßqÏ$>•î íZ¥Z 1{ç൵+ƒÕµ¥°T$§K]á»Ûï*·¤tMI’ÂZbŽÕiÒ˜}bÓ0£ª5›¨ [5Ž^ÝœWøÂÝh° ¢OWun£¤5 a2Z.G2³YL]jåtì”ä ÁÓ‘%"©<Ôúʰsº UZvä‡ÄiÆÒM .÷V·™ø#kèýiíÌ–ª)µT[)BˆõÑ xB¾B€ÖT¨.¥~ð@VĶr#¸ü*åZNDŽH;âi ],©£öØpù(šºãö¼T.uCê•4@ÿ GÕÛ)Cx›®0ø#:ÏðFÒbR\(€€Ä®fã4Þ‰Fä¯HXƒÅ,†öEÑÔÜ]Öv²?tLÃvBY£ú6Êu5ÅAQ³1‘’¬x–HŒÐ‡ ^ ¸KwJôÖŽ5×CÚ¨vÜ«/B0$×k°=ðbÇ(Ï)w±A†Á† 11Í=èQšµ626ŒÜ/`G«µ<}—-Ö7KEHÈÉðóȤmݱû±·ø«Snmá=“䫚mݱŸ¡¶~ó·“äUóJæúòB|E LêŽy´jDÔ$G¢þÐñ7óR8ýÒ…Ç› WVe#·Ÿ p·Fx~•ݤF÷0Èÿ K¯æS<6’¡WШ; ´ÿ ¥Êø\Òuî†åÝ–VNœkÒ7oòX¨Á­Ø÷FÎÑä±g÷ÿ M~Çî=p,X´ ÝÌÚÅ‹’ÃjÖ.ØöÏñ qïQ¤ÓZE†° =6·]܈ s¸>v•Ž^Ý\wq9r‰Î\¸¡kURÒ$­*‹Nq?Þª*!sŠÆ:TU_u±T+øX¡ ®¹¡,ÄâÃBTsÜ$Ø›4m椴zÜK]’’›Pƒ @€#â˜`é¹=I‡fiV•Ôî“nRm+µFPOhÍ0B£ €+¬5c v•:P'ÒyÎ ‰V~‚Ó†ÖuókDoh$å\*ö%Ю=£«…aȼ½÷Û.-½VŒŠ¼'lyî±1¬3ó#ÞE¿ÔS¤gV£m›=§\û"—WU¤ÚǼÿ ÂnÁGŒÃ ‚õN D³õNÚíŒÕ;HôyÄÈ©P¹Ä{:?R‘Ô¨âF÷ø£bÅó® JS|‚R÷ivýáâ€Æé¡è³´IئÑT!§˜•ت‚¬â@q€wnïCWÄ@JU€ê¯m6]Ï:£âx'+ÒðXvÓ¦Úm=–´7œ $ì“B£~p%ÕŸUþ« N@¼üï~w˜ñø5®—'Ôe»¤5ã//€ž~‰Tþ›Å7•#¤× Íö pÄ$ùeåì*«ÓŠEØWEÈsßg ¦ûvžSsLpºÊW–âµEWöˬH; ™!CYõZ ÃÄf æ#1W. \uWâ\,\Çf j’<qTbên›Î[vxx£ë 'ö¨1›˜ÀM¼Pÿ H)ƒêêŒA7s,|F“ 꺸k³9Ìö*ç®;Ö!Ö$Eiž•¹ÒÚ†ýóéÝû¾ÕS®ó$’NÝäŸz¤5r¦ãÄÃD÷Üø!°ø‡Ô&@m™Ì^Ãä­d q5Lnÿ N;.6½·N|#ä"1Nƒx“ã<3('&ñßt  ~ªu”1Tb㫨9ê–›–bìd$ߣ=#ÕãÒmU¯eí$EFù5ýYô櫨æì™Ç—±ssM]·á¿0ÕåJRÓªîiƒ+O58ÖñªŠÒx" \µâá¨i’¤i —Ö ” M+M¤ë9‚‰A¦°Qõ¾ßøK~¼Ã‘g…Ö´~÷Ï[3GUœÒ½#…kàÔ®Ò”‰³·dWV‰IP‰Ú8u¹”E ÖqLj¾êÕCBš{A^Âß;–¨`¯¬ìö ˼ ×tìø.tƐm*n¨y4o&Àx¥n¦×î‡aupáÛj8¿m›è¶ã!o½;ß0y^ý×^EÑ¿ÒjzŒ­)vÚÑnÄL …^ªô× ‡—‚3k Îý­hï]içå–îÏ*÷ñþ»Ô CÒjøjÍznˆ´ ¹#b'Fô‹ ‰v¥'’à'T´ƒHýÍ%M‰ ƒ&ÆÇŒï1 ‘ –Þ ‰i¬s žR-Ÿ kЬá¬7:þ 0ŒÅÒÕ/aÙ¬ÃÝ#Úøœ ©aiVc‰. ¹¦ãµ” ›Yg¦›ÆÎýº°f³7ƒhá·¸­}&D9¡ÂsÉÙÞèŠõØàC™¨ñbFC|´Ü(ŸƒÚÒ-%»'a Ì¿)ËÇn¿úÿ ÞŽX…4ÊÅH^ôΑí@ù¹Eh¶“L8Çjù ¼ÎåVªóR©Ï5uà V4lZß®=€xÖŸ–ÑÈ ÷”¨°¾__yM1tÉ?uÆþIkÄgæ@þ[¢†°XÃJ£j·:nkÅ¢u ‘}âGzö­/IµèЬ¼48q¦F°ŽR¼=ûì{´¯RýicS ÕÛ íNtÍÙï£,w4rêì®»~x(©Uñ§#Ñ&œÕ¤>ÎåÍÓ9’Ö{9eV­[Öjâ²ãu]˜å2›qÑšÕJç0€sÄ|Êëè0튔bÁ>“{×_F`Ø©ºê:µä,v¤ðfc1±"«ÔÍän1#=· Âøv~H½ÐßA¾¿Ü€Óš]Õ; I¾÷ç‚Qi†î¹9ywÔKG˜áñ zQY—§ÃÕZ07§X‚ Áh;ÁM)iÌCH-¯T‘ë|A0{Ò½LÚ–TâÖkÜ’dÀ“rmm»”جPF³ÖcbE§T€ÒxKºû’Ó®7±²(\4ŽÃ¸Uu@j™yĵ;³µ!Á¢b.W¤=mõ´êµK k ¸K^ÜÛ#p*Ü14qkZç5ïë †°5Ï%ÍÛ<Õ¤×Ô¥ê†C Õ´¼ú$ƒÖ“”]Ù¬qÞÚ[4©ý!ûÏ—Áb쳐XµA¬â~`›Çr¸8ìùÝ䫦<>ä÷«?xs´ÇÑ /á;¹øüÊÈÙà{"@Žïzâ¬[âß‚ U_<ÇŸ½4èN˜ú61®qŠu ¦þF£»äJ_ˆÙÎ~ ÞAã–݄ϗrŠD;xTž‘ô`É«…suãO`?³à™ô Lý#Íc5öoæØ‚y´´÷«ZR§<&JÇ+éâô´€i!Àˆ0æAoàðLèÖ-2ŸõW.’t^–(KÁmHµV@xÜÇy®Ñø­â^:Ú3w· 7½¹°ñ¸â¹®:',«Mœ—n­Á+Ãbš LÈ‘ÄnRÓÅœ%¦²‰¨ùQ:¤f‚ "PÕtô¸…cæl…&˜Ú˜Ôkv‹ž+vŠ,=¢v­6—Xy*¥t£«<™:“aîϲ=¦6rO]XI¿Œ÷¤zÚ­›¶ 6÷”w\d ü~v®ˆÌk«^m<ÿ ¢‰Õ\)ùºŽ;… lîÙÅEŠ®cѾ@vnMÏ,¼“ñ•ŽBxðÃzãÇç%3ˆ"}Ù•Åî> BÉú;Ò]V+P˜F_´ßé> Øše|ï‡ÄOmFæÇ ãqÞ$/xÐx­z`ï9"œÜij‚!7.\Td…9M‡•iŽ‹¾‘50ÞŽn¥ß4ÉôO ¹*í^QêËÜÇÌ8=ާs‰'ÂëÙ«á%Pú[O †ÅP¯Vsް.‰,kc¶ ¬A9n˜XÎ-ÞšN["¹QÕ‰ƒMýÁߺXJæÍaLj¾×Ãmã¾ãÚ uñÒþåQô¦¥ /ÄUx:‚ÍÜ’ Đ©ØÝ3V¨‰ÕnÐ6ó*óúK­«…c ¯U òhsý­jóÔj#,ímŒRµ«lbïUTŒÑ8†Ä0œÏr`ð¡¬É Ї ë"À² ™ 6¥ f¶ ¢ÚoܱԷ-<Àî)†a¶ž'Ú»¨TXqØæ¶÷YÄHy˜9ÈIW­YÀuMFë ºÏ’AqÌ4·/Ú †ô'i$øä­=Ä Ý|öK×40è|È6p‘0§)o¥ctî§H+CA-“ xØ|ÐXАç l8íºð3Ø:³¤¬KX¯UÿÙ # coding: utf-8 """ ASN.1 type classes for public and private keys. Exports the following items: - DSAPrivateKey() - ECPrivateKey() - EncryptedPrivateKeyInfo() - PrivateKeyInfo() - PublicKeyInfo() - RSAPrivateKey() - RSAPublicKey() Other type classes are defined that help compose the types listed above. """ from __future__ import unicode_literals, division, absolute_import, print_function import hashlib import math from ._elliptic_curve import ( SECP192R1_BASE_POINT, SECP224R1_BASE_POINT, SECP256R1_BASE_POINT, SECP384R1_BASE_POINT, SECP521R1_BASE_POINT, PrimeCurve, PrimePoint, ) from ._errors import unwrap from ._types import type_name, str_cls, byte_cls from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams from .core import ( Any, Asn1Value, BitString, Choice, Integer, IntegerOctetString, Null, ObjectIdentifier, OctetBitString, OctetString, ParsableOctetString, ParsableOctetBitString, Sequence, SequenceOf, SetOf, ) from .util import int_from_bytes, int_to_bytes class OtherPrimeInfo(Sequence): """ Source: https://tools.ietf.org/html/rfc3447#page-46 """ _fields = [ ('prime', Integer), ('exponent', Integer), ('coefficient', Integer), ] class OtherPrimeInfos(SequenceOf): """ Source: https://tools.ietf.org/html/rfc3447#page-46 """ _child_spec = OtherPrimeInfo class RSAPrivateKeyVersion(Integer): """ Original Name: Version Source: https://tools.ietf.org/html/rfc3447#page-45 """ _map = { 0: 'two-prime', 1: 'multi', } class RSAPrivateKey(Sequence): """ Source: https://tools.ietf.org/html/rfc3447#page-45 """ _fields = [ ('version', RSAPrivateKeyVersion), ('modulus', Integer), ('public_exponent', Integer), ('private_exponent', Integer), ('prime1', Integer), ('prime2', Integer), ('exponent1', Integer), ('exponent2', Integer), ('coefficient', Integer), ('other_prime_infos', OtherPrimeInfos, {'optional': True}) ] class RSAPublicKey(Sequence): """ Source: https://tools.ietf.org/html/rfc3447#page-44 """ _fields = [ ('modulus', Integer), ('public_exponent', Integer) ] class DSAPrivateKey(Sequence): """ The ASN.1 structure that OpenSSL uses to store a DSA private key that is not part of a PKCS#8 structure. Reversed engineered from english-language description on linked OpenSSL documentation page. Original Name: None Source: https://www.openssl.org/docs/apps/dsa.html """ _fields = [ ('version', Integer), ('p', Integer), ('q', Integer), ('g', Integer), ('public_key', Integer), ('private_key', Integer), ] class _ECPoint(): """ In both PublicKeyInfo and PrivateKeyInfo, the EC public key is a byte string that is encoded as a bit string. This class adds convenience methods for converting to and from the byte string to a pair of integers that are the X and Y coordinates. """ @classmethod def from_coords(cls, x, y): """ Creates an ECPoint object from the X and Y integer coordinates of the point :param x: The X coordinate, as an integer :param y: The Y coordinate, as an integer :return: An ECPoint object """ x_bytes = int(math.ceil(math.log(x, 2) / 8.0)) y_bytes = int(math.ceil(math.log(y, 2) / 8.0)) num_bytes = max(x_bytes, y_bytes) byte_string = b'\x04' byte_string += int_to_bytes(x, width=num_bytes) byte_string += int_to_bytes(y, width=num_bytes) return cls(byte_string) def to_coords(self): """ Returns the X and Y coordinates for this EC point, as native Python integers :return: A 2-element tuple containing integers (X, Y) """ data = self.native first_byte = data[0:1] # Uncompressed if first_byte == b'\x04': remaining = data[1:] field_len = len(remaining) // 2 x = int_from_bytes(remaining[0:field_len]) y = int_from_bytes(remaining[field_len:]) return (x, y) if first_byte not in set([b'\x02', b'\x03']): raise ValueError(unwrap( ''' Invalid EC public key - first byte is incorrect ''' )) raise ValueError(unwrap( ''' Compressed representations of EC public keys are not supported due to patent US6252960 ''' )) class ECPoint(OctetString, _ECPoint): pass class ECPointBitString(OctetBitString, _ECPoint): pass class SpecifiedECDomainVersion(Integer): """ Source: http://www.secg.org/sec1-v2.pdf page 104 """ _map = { 1: 'ecdpVer1', 2: 'ecdpVer2', 3: 'ecdpVer3', } class FieldType(ObjectIdentifier): """ Original Name: None Source: http://www.secg.org/sec1-v2.pdf page 101 """ _map = { '1.2.840.10045.1.1': 'prime_field', '1.2.840.10045.1.2': 'characteristic_two_field', } class CharacteristicTwoBasis(ObjectIdentifier): """ Original Name: None Source: http://www.secg.org/sec1-v2.pdf page 102 """ _map = { '1.2.840.10045.1.2.1.1': 'gn_basis', '1.2.840.10045.1.2.1.2': 'tp_basis', '1.2.840.10045.1.2.1.3': 'pp_basis', } class Pentanomial(Sequence): """ Source: http://www.secg.org/sec1-v2.pdf page 102 """ _fields = [ ('k1', Integer), ('k2', Integer), ('k3', Integer), ] class CharacteristicTwo(Sequence): """ Original Name: Characteristic-two Source: http://www.secg.org/sec1-v2.pdf page 101 """ _fields = [ ('m', Integer), ('basis', CharacteristicTwoBasis), ('parameters', Any), ] _oid_pair = ('basis', 'parameters') _oid_specs = { 'gn_basis': Null, 'tp_basis': Integer, 'pp_basis': Pentanomial, } class FieldID(Sequence): """ Source: http://www.secg.org/sec1-v2.pdf page 100 """ _fields = [ ('field_type', FieldType), ('parameters', Any), ] _oid_pair = ('field_type', 'parameters') _oid_specs = { 'prime_field': Integer, 'characteristic_two_field': CharacteristicTwo, } class Curve(Sequence): """ Source: http://www.secg.org/sec1-v2.pdf page 104 """ _fields = [ ('a', OctetString), ('b', OctetString), ('seed', OctetBitString, {'optional': True}), ] class SpecifiedECDomain(Sequence): """ Source: http://www.secg.org/sec1-v2.pdf page 103 """ _fields = [ ('version', SpecifiedECDomainVersion), ('field_id', FieldID), ('curve', Curve), ('base', ECPoint), ('order', Integer), ('cofactor', Integer, {'optional': True}), ('hash', DigestAlgorithm, {'optional': True}), ] class NamedCurve(ObjectIdentifier): """ Various named curves Original Name: None Source: https://tools.ietf.org/html/rfc3279#page-23, https://tools.ietf.org/html/rfc5480#page-5 """ _map = { # https://tools.ietf.org/html/rfc3279#page-23 '1.2.840.10045.3.0.1': 'c2pnb163v1', '1.2.840.10045.3.0.2': 'c2pnb163v2', '1.2.840.10045.3.0.3': 'c2pnb163v3', '1.2.840.10045.3.0.4': 'c2pnb176w1', '1.2.840.10045.3.0.5': 'c2tnb191v1', '1.2.840.10045.3.0.6': 'c2tnb191v2', '1.2.840.10045.3.0.7': 'c2tnb191v3', '1.2.840.10045.3.0.8': 'c2onb191v4', '1.2.840.10045.3.0.9': 'c2onb191v5', '1.2.840.10045.3.0.10': 'c2pnb208w1', '1.2.840.10045.3.0.11': 'c2tnb239v1', '1.2.840.10045.3.0.12': 'c2tnb239v2', '1.2.840.10045.3.0.13': 'c2tnb239v3', '1.2.840.10045.3.0.14': 'c2onb239v4', '1.2.840.10045.3.0.15': 'c2onb239v5', '1.2.840.10045.3.0.16': 'c2pnb272w1', '1.2.840.10045.3.0.17': 'c2pnb304w1', '1.2.840.10045.3.0.18': 'c2tnb359v1', '1.2.840.10045.3.0.19': 'c2pnb368w1', '1.2.840.10045.3.0.20': 'c2tnb431r1', '1.2.840.10045.3.1.2': 'prime192v2', '1.2.840.10045.3.1.3': 'prime192v3', '1.2.840.10045.3.1.4': 'prime239v1', '1.2.840.10045.3.1.5': 'prime239v2', '1.2.840.10045.3.1.6': 'prime239v3', # https://tools.ietf.org/html/rfc5480#page-5 '1.3.132.0.1': 'sect163k1', '1.3.132.0.15': 'sect163r2', '1.2.840.10045.3.1.1': 'secp192r1', '1.3.132.0.33': 'secp224r1', '1.3.132.0.26': 'sect233k1', '1.2.840.10045.3.1.7': 'secp256r1', '1.3.132.0.27': 'sect233r1', '1.3.132.0.16': 'sect283k1', '1.3.132.0.17': 'sect283r1', '1.3.132.0.34': 'secp384r1', '1.3.132.0.36': 'sect409k1', '1.3.132.0.37': 'sect409r1', '1.3.132.0.35': 'secp521r1', '1.3.132.0.38': 'sect571k1', '1.3.132.0.39': 'sect571r1', } class ECDomainParameters(Choice): """ Source: http://www.secg.org/sec1-v2.pdf page 102 """ _alternatives = [ ('specified', SpecifiedECDomain), ('named', NamedCurve), ('implicit_ca', Null), ] class ECPrivateKeyVersion(Integer): """ Original Name: None Source: http://www.secg.org/sec1-v2.pdf page 108 """ _map = { 1: 'ecPrivkeyVer1', } class ECPrivateKey(Sequence): """ Source: http://www.secg.org/sec1-v2.pdf page 108 """ _fields = [ ('version', ECPrivateKeyVersion), ('private_key', IntegerOctetString), ('parameters', ECDomainParameters, {'explicit': 0, 'optional': True}), ('public_key', ECPointBitString, {'explicit': 1, 'optional': True}), ] class DSAParams(Sequence): """ Parameters for a DSA public or private key Original Name: Dss-Parms Source: https://tools.ietf.org/html/rfc3279#page-9 """ _fields = [ ('p', Integer), ('q', Integer), ('g', Integer), ] class Attribute(Sequence): """ Source: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.501-198811-S!!PDF-E&type=items page 8 """ _fields = [ ('type', ObjectIdentifier), ('values', SetOf, {'spec': Any}), ] class Attributes(SetOf): """ Source: https://tools.ietf.org/html/rfc5208#page-3 """ _child_spec = Attribute class PrivateKeyAlgorithmId(ObjectIdentifier): """ These OIDs for various public keys are reused when storing private keys inside of a PKCS#8 structure Original Name: None Source: https://tools.ietf.org/html/rfc3279 """ _map = { # https://tools.ietf.org/html/rfc3279#page-19 '1.2.840.113549.1.1.1': 'rsa', # https://tools.ietf.org/html/rfc3279#page-18 '1.2.840.10040.4.1': 'dsa', # https://tools.ietf.org/html/rfc3279#page-13 '1.2.840.10045.2.1': 'ec', } class PrivateKeyAlgorithm(_ForceNullParameters, Sequence): """ Original Name: PrivateKeyAlgorithmIdentifier Source: https://tools.ietf.org/html/rfc5208#page-3 """ _fields = [ ('algorithm', PrivateKeyAlgorithmId), ('parameters', Any, {'optional': True}), ] _oid_pair = ('algorithm', 'parameters') _oid_specs = { 'dsa': DSAParams, 'ec': ECDomainParameters, } class PrivateKeyInfo(Sequence): """ Source: https://tools.ietf.org/html/rfc5208#page-3 """ _fields = [ ('version', Integer), ('private_key_algorithm', PrivateKeyAlgorithm), ('private_key', ParsableOctetString), ('attributes', Attributes, {'implicit': 0, 'optional': True}), ] def _private_key_spec(self): algorithm = self['private_key_algorithm']['algorithm'].native return { 'rsa': RSAPrivateKey, 'dsa': Integer, 'ec': ECPrivateKey, }[algorithm] _spec_callbacks = { 'private_key': _private_key_spec } _algorithm = None _bit_size = None _public_key = None _fingerprint = None @classmethod def wrap(cls, private_key, algorithm): """ Wraps a private key in a PrivateKeyInfo structure :param private_key: A byte string or Asn1Value object of the private key :param algorithm: A unicode string of "rsa", "dsa" or "ec" :return: A PrivateKeyInfo object """ if not isinstance(private_key, byte_cls) and not isinstance(private_key, Asn1Value): raise TypeError(unwrap( ''' private_key must be a byte string or Asn1Value, not %s ''', type_name(private_key) )) if algorithm == 'rsa': if not isinstance(private_key, RSAPrivateKey): private_key = RSAPrivateKey.load(private_key) params = Null() elif algorithm == 'dsa': if not isinstance(private_key, DSAPrivateKey): private_key = DSAPrivateKey.load(private_key) params = DSAParams() params['p'] = private_key['p'] params['q'] = private_key['q'] params['g'] = private_key['g'] public_key = private_key['public_key'] private_key = private_key['private_key'] elif algorithm == 'ec': if not isinstance(private_key, ECPrivateKey): private_key = ECPrivateKey.load(private_key) else: private_key = private_key.copy() params = private_key['parameters'] del private_key['parameters'] else: raise ValueError(unwrap( ''' algorithm must be one of "rsa", "dsa", "ec", not %s ''', repr(algorithm) )) private_key_algo = PrivateKeyAlgorithm() private_key_algo['algorithm'] = PrivateKeyAlgorithmId(algorithm) private_key_algo['parameters'] = params container = cls() container._algorithm = algorithm container['version'] = Integer(0) container['private_key_algorithm'] = private_key_algo container['private_key'] = private_key # Here we save the DSA public key if possible since it is not contained # within the PKCS#8 structure for a DSA key if algorithm == 'dsa': container._public_key = public_key return container def _compute_public_key(self): """ Computes the public key corresponding to the current private key. :return: For RSA keys, an RSAPublicKey object. For DSA keys, an Integer object. For EC keys, an ECPointBitString. """ if self.algorithm == 'dsa': params = self['private_key_algorithm']['parameters'] return Integer(pow( params['g'].native, self['private_key'].parsed.native, params['p'].native )) if self.algorithm == 'rsa': key = self['private_key'].parsed return RSAPublicKey({ 'modulus': key['modulus'], 'public_exponent': key['public_exponent'], }) if self.algorithm == 'ec': curve_type, details = self.curve if curve_type == 'implicit_ca': raise ValueError(unwrap( ''' Unable to compute public key for EC key using Implicit CA parameters ''' )) if curve_type == 'specified': if details['field_id']['field_type'] == 'characteristic_two_field': raise ValueError(unwrap( ''' Unable to compute public key for EC key over a characteristic two field ''' )) curve = PrimeCurve( details['field_id']['parameters'], int_from_bytes(details['curve']['a']), int_from_bytes(details['curve']['b']) ) base_x, base_y = self['private_key_algorithm']['parameters'].chosen['base'].to_coords() base_point = PrimePoint(curve, base_x, base_y) elif curve_type == 'named': if details not in ('secp192r1', 'secp224r1', 'secp256r1', 'secp384r1', 'secp521r1'): raise ValueError(unwrap( ''' Unable to compute public key for EC named curve %s, parameters not currently included ''', details )) base_point = { 'secp192r1': SECP192R1_BASE_POINT, 'secp224r1': SECP224R1_BASE_POINT, 'secp256r1': SECP256R1_BASE_POINT, 'secp384r1': SECP384R1_BASE_POINT, 'secp521r1': SECP521R1_BASE_POINT, }[details] public_point = base_point * self['private_key'].parsed['private_key'].native return ECPointBitString.from_coords(public_point.x, public_point.y) def unwrap(self): """ Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or ECPrivateKey object :return: An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object """ if self.algorithm == 'rsa': return self['private_key'].parsed if self.algorithm == 'dsa': params = self['private_key_algorithm']['parameters'] return DSAPrivateKey({ 'version': 0, 'p': params['p'], 'q': params['q'], 'g': params['g'], 'public_key': self.public_key, 'private_key': self['private_key'].parsed, }) if self.algorithm == 'ec': output = self['private_key'].parsed output['parameters'] = self['private_key_algorithm']['parameters'] output['public_key'] = self.public_key return output @property def curve(self): """ Returns information about the curve used for an EC key :raises: ValueError - when the key is not an EC key :return: A two-element tuple, with the first element being a unicode string of "implicit_ca", "specified" or "named". If the first element is "implicit_ca", the second is None. If "specified", the second is an OrderedDict that is the native version of SpecifiedECDomain. If "named", the second is a unicode string of the curve name. """ if self.algorithm != 'ec': raise ValueError(unwrap( ''' Only EC keys have a curve, this key is %s ''', self.algorithm.upper() )) params = self['private_key_algorithm']['parameters'] chosen = params.chosen if params.name == 'implicit_ca': value = None else: value = chosen.native return (params.name, value) @property def hash_algo(self): """ Returns the name of the family of hash algorithms used to generate a DSA key :raises: ValueError - when the key is not a DSA key :return: A unicode string of "sha1" or "sha2" """ if self.algorithm != 'dsa': raise ValueError(unwrap( ''' Only DSA keys are generated using a hash algorithm, this key is %s ''', self.algorithm.upper() )) byte_len = math.log(self['private_key_algorithm']['parameters']['q'].native, 2) / 8 return 'sha1' if byte_len <= 20 else 'sha2' @property def algorithm(self): """ :return: A unicode string of "rsa", "dsa" or "ec" """ if self._algorithm is None: self._algorithm = self['private_key_algorithm']['algorithm'].native return self._algorithm @property def bit_size(self): """ :return: The bit size of the private key, as an integer """ if self._bit_size is None: if self.algorithm == 'rsa': prime = self['private_key'].parsed['modulus'].native elif self.algorithm == 'dsa': prime = self['private_key_algorithm']['parameters']['p'].native elif self.algorithm == 'ec': prime = self['private_key'].parsed['private_key'].native self._bit_size = int(math.ceil(math.log(prime, 2))) modulus = self._bit_size % 8 if modulus != 0: self._bit_size += 8 - modulus return self._bit_size @property def byte_size(self): """ :return: The byte size of the private key, as an integer """ return int(math.ceil(self.bit_size / 8)) @property def public_key(self): """ :return: If an RSA key, an RSAPublicKey object. If a DSA key, an Integer object. If an EC key, an ECPointBitString object. """ if self._public_key is None: if self.algorithm == 'ec': key = self['private_key'].parsed if key['public_key']: self._public_key = key['public_key'].untag() else: self._public_key = self._compute_public_key() else: self._public_key = self._compute_public_key() return self._public_key @property def public_key_info(self): """ :return: A PublicKeyInfo object derived from this private key. """ return PublicKeyInfo({ 'algorithm': { 'algorithm': self.algorithm, 'parameters': self['private_key_algorithm']['parameters'] }, 'public_key': self.public_key }) @property def fingerprint(self): """ Creates a fingerprint that can be compared with a public key to see if the two form a pair. This fingerprint is not compatible with fingerprints generated by any other software. :return: A byte string that is a sha256 hash of selected components (based on the key type) """ if self._fingerprint is None: params = self['private_key_algorithm']['parameters'] key = self['private_key'].parsed if self.algorithm == 'rsa': to_hash = '%d:%d' % ( key['modulus'].native, key['public_exponent'].native, ) elif self.algorithm == 'dsa': public_key = self.public_key to_hash = '%d:%d:%d:%d' % ( params['p'].native, params['q'].native, params['g'].native, public_key.native, ) elif self.algorithm == 'ec': public_key = key['public_key'].native if public_key is None: public_key = self.public_key.native if params.name == 'named': to_hash = '%s:' % params.chosen.native to_hash = to_hash.encode('utf-8') to_hash += public_key elif params.name == 'implicit_ca': to_hash = public_key elif params.name == 'specified': to_hash = '%s:' % params.chosen['field_id']['parameters'].native to_hash = to_hash.encode('utf-8') to_hash += b':' + params.chosen['curve']['a'].native to_hash += b':' + params.chosen['curve']['b'].native to_hash += public_key if isinstance(to_hash, str_cls): to_hash = to_hash.encode('utf-8') self._fingerprint = hashlib.sha256(to_hash).digest() return self._fingerprint class EncryptedPrivateKeyInfo(Sequence): """ Source: https://tools.ietf.org/html/rfc5208#page-4 """ _fields = [ ('encryption_algorithm', EncryptionAlgorithm), ('encrypted_data', OctetString), ] # These structures are from https://tools.ietf.org/html/rfc3279 class ValidationParms(Sequence): """ Source: https://tools.ietf.org/html/rfc3279#page-10 """ _fields = [ ('seed', BitString), ('pgen_counter', Integer), ] class DomainParameters(Sequence): """ Source: https://tools.ietf.org/html/rfc3279#page-10 """ _fields = [ ('p', Integer), ('g', Integer), ('q', Integer), ('j', Integer, {'optional': True}), ('validation_params', ValidationParms, {'optional': True}), ] class PublicKeyAlgorithmId(ObjectIdentifier): """ Original Name: None Source: https://tools.ietf.org/html/rfc3279 """ _map = { # https://tools.ietf.org/html/rfc3279#page-19 '1.2.840.113549.1.1.1': 'rsa', # https://tools.ietf.org/html/rfc3447#page-47 '1.2.840.113549.1.1.7': 'rsaes_oaep', # https://tools.ietf.org/html/rfc3279#page-18 '1.2.840.10040.4.1': 'dsa', # https://tools.ietf.org/html/rfc3279#page-13 '1.2.840.10045.2.1': 'ec', # https://tools.ietf.org/html/rfc3279#page-10 '1.2.840.10046.2.1': 'dh', } class PublicKeyAlgorithm(_ForceNullParameters, Sequence): """ Original Name: AlgorithmIdentifier Source: https://tools.ietf.org/html/rfc5280#page-18 """ _fields = [ ('algorithm', PublicKeyAlgorithmId), ('parameters', Any, {'optional': True}), ] _oid_pair = ('algorithm', 'parameters') _oid_specs = { 'dsa': DSAParams, 'ec': ECDomainParameters, 'dh': DomainParameters, 'rsaes_oaep': RSAESOAEPParams, } class PublicKeyInfo(Sequence): """ Original Name: SubjectPublicKeyInfo Source: https://tools.ietf.org/html/rfc5280#page-17 """ _fields = [ ('algorithm', PublicKeyAlgorithm), ('public_key', ParsableOctetBitString), ] def _public_key_spec(self): algorithm = self['algorithm']['algorithm'].native return { 'rsa': RSAPublicKey, 'rsaes_oaep': RSAPublicKey, 'dsa': Integer, # We override the field spec with ECPoint so that users can easily # decompose the byte string into the constituent X and Y coords 'ec': (ECPointBitString, None), 'dh': Integer, }[algorithm] _spec_callbacks = { 'public_key': _public_key_spec } _algorithm = None _bit_size = None _fingerprint = None _sha1 = None _sha256 = None @classmethod def wrap(cls, public_key, algorithm): """ Wraps a public key in a PublicKeyInfo structure :param public_key: A byte string or Asn1Value object of the public key :param algorithm: A unicode string of "rsa" :return: A PublicKeyInfo object """ if not isinstance(public_key, byte_cls) and not isinstance(public_key, Asn1Value): raise TypeError(unwrap( ''' public_key must be a byte string or Asn1Value, not %s ''', type_name(public_key) )) if algorithm != 'rsa': raise ValueError(unwrap( ''' algorithm must "rsa", not %s ''', repr(algorithm) )) algo = PublicKeyAlgorithm() algo['algorithm'] = PublicKeyAlgorithmId(algorithm) algo['parameters'] = Null() container = cls() container['algorithm'] = algo if isinstance(public_key, Asn1Value): public_key = public_key.untag().dump() container['public_key'] = ParsableOctetBitString(public_key) return container def unwrap(self): """ Unwraps an RSA public key into an RSAPublicKey object. Does not support DSA or EC public keys since they do not have an unwrapped form. :return: An RSAPublicKey object """ if self.algorithm == 'rsa': return self['public_key'].parsed key_type = self.algorithm.upper() a_an = 'an' if key_type == 'EC' else 'a' raise ValueError(unwrap( ''' Only RSA public keys may be unwrapped - this key is %s %s public key ''', a_an, key_type )) @property def curve(self): """ Returns information about the curve used for an EC key :raises: ValueError - when the key is not an EC key :return: A two-element tuple, with the first element being a unicode string of "implicit_ca", "specified" or "named". If the first element is "implicit_ca", the second is None. If "specified", the second is an OrderedDict that is the native version of SpecifiedECDomain. If "named", the second is a unicode string of the curve name. """ if self.algorithm != 'ec': raise ValueError(unwrap( ''' Only EC keys have a curve, this key is %s ''', self.algorithm.upper() )) params = self['algorithm']['parameters'] chosen = params.chosen if params.name == 'implicit_ca': value = None else: value = chosen.native return (params.name, value) @property def hash_algo(self): """ Returns the name of the family of hash algorithms used to generate a DSA key :raises: ValueError - when the key is not a DSA key :return: A unicode string of "sha1" or "sha2" or None if no parameters are present """ if self.algorithm != 'dsa': raise ValueError(unwrap( ''' Only DSA keys are generated using a hash algorithm, this key is %s ''', self.algorithm.upper() )) parameters = self['algorithm']['parameters'] if parameters.native is None: return None byte_len = math.log(parameters['q'].native, 2) / 8 return 'sha1' if byte_len <= 20 else 'sha2' @property def algorithm(self): """ :return: A unicode string of "rsa", "dsa" or "ec" """ if self._algorithm is None: self._algorithm = self['algorithm']['algorithm'].native return self._algorithm @property def bit_size(self): """ :return: The bit size of the public key, as an integer """ if self._bit_size is None: if self.algorithm == 'ec': self._bit_size = ((len(self['public_key'].native) - 1) / 2) * 8 else: if self.algorithm == 'rsa': prime = self['public_key'].parsed['modulus'].native elif self.algorithm == 'dsa': prime = self['algorithm']['parameters']['p'].native self._bit_size = int(math.ceil(math.log(prime, 2))) modulus = self._bit_size % 8 if modulus != 0: self._bit_size += 8 - modulus return self._bit_size @property def byte_size(self): """ :return: The byte size of the public key, as an integer """ return int(math.ceil(self.bit_size / 8)) @property def sha1(self): """ :return: The SHA1 hash of the DER-encoded bytes of this public key info """ if self._sha1 is None: self._sha1 = hashlib.sha1(byte_cls(self['public_key'])).digest() return self._sha1 @property def sha256(self): """ :return: The SHA-256 hash of the DER-encoded bytes of this public key info """ if self._sha256 is None: self._sha256 = hashlib.sha256(byte_cls(self['public_key'])).digest() return self._sha256 @property def fingerprint(self): """ Creates a fingerprint that can be compared with a private key to see if the two form a pair. This fingerprint is not compatible with fingerprints generated by any other software. :return: A byte string that is a sha256 hash of selected components (based on the key type) """ if self._fingerprint is None: key_type = self['algorithm']['algorithm'].native params = self['algorithm']['parameters'] if key_type == 'rsa': key = self['public_key'].parsed to_hash = '%d:%d' % ( key['modulus'].native, key['public_exponent'].native, ) elif key_type == 'dsa': key = self['public_key'].parsed to_hash = '%d:%d:%d:%d' % ( params['p'].native, params['q'].native, params['g'].native, key.native, ) elif key_type == 'ec': key = self['public_key'] if params.name == 'named': to_hash = '%s:' % params.chosen.native to_hash = to_hash.encode('utf-8') to_hash += key.native elif params.name == 'implicit_ca': to_hash = key.native elif params.name == 'specified': to_hash = '%s:' % params.chosen['field_id']['parameters'].native to_hash = to_hash.encode('utf-8') to_hash += b':' + params.chosen['curve']['a'].native to_hash += b':' + params.chosen['curve']['b'].native to_hash += key.native if isinstance(to_hash, str_cls): to_hash = to_hash.encode('utf-8') self._fingerprint = hashlib.sha256(to_hash).digest() return self._fingerprint