ÿØÿà JFIF    ÿÛ „ !.%+&8&+/1555$;@;4?.451 4,$,44444444444414444444444444444444444444444444444444ÿÀ  á á" ÿÄ     ÿÄ ?    !1AQaq"2‘¡±ÁðBRbrÑá#‚’¢²3S CñÿÄ   ÿÄ !    !1QAa‘2ÿÚ   ? 5˜Z¯V¦cø)›t/? z¨±>Õ5€¶‹Á¤·¼z¼Ü¬+ñ®v¤¨_ˆR­BFn©—˜ý®ç̝P8gýt·ÉSTŦˆìät?þé¼íìN/Þa)ì–í6ô… Ï¿øÃj´¿KÇü]ÿ ªô¹-eKànëÕHTx}ýSÜ›ÿ ”7Ø×&µ<¦  ¥ÑO¶[Ù¯ä¨ÞÃÿ PZ-¬;#õ|•oaÿ ©CìÞz3˜öː/¤­ñTûIØ}š^ mÓ%ªxˆ¥ÉŸu=Z+ISe¿45™¼u;ú&WØ÷€æßQ™®{|íx*TC“#ZŠìZ§²‹ 6pv…³¿¡äª*áZÐ%ÒOáˆo"x«OHk w±æ+¬V(kMúŸ5Vö«$ ÁrÏbàb57/luR ¸ÑÛj Òµì`Мq­û žICÀÊ•©4€Âcà¨Ï€O´<èÐ:›ù(Ë^L8þ‘ÍÌ#¸Ð_Ì©ÙK(Öz 4¬û+¸;ü’V’84‘¬ÃŽ:[â‡ÔÌáõp¢~§ªlæ£ö{®G>J¼"°‡7¯ÆÉèßû ‹É‹§ÁòÃýâßî ^ƾÙõ‹×óH#«LP½ïX=xÑÍ$|W?•~• îëÔ©ª‹ {ÝT…Kÿ ”hûâá)J*ö˜–ÔU;iÇ€/ ÆþjóZ\ýwØ=Ìm ºèËL9 ýèÆð/¨’¥öo=nË.%Îì ŽÕ¯È|{Oj²ƒE6e/ßdÄõ²Ìâ1O®ò×TsəԸhOMýíMˆ¿¼H˜l²,7Â¥#MF/Úf°Ö½± ¸–dr‹NýÊ íjqx{œÉ ä-È ¦ øÄër¨q°ð †nцýÑÄÆ’mä…n<0È™;ÁÝá¯ÁZƒ7FÀmì­ É&9ˆîéi¶ùN§Y• ÃZãAâ?•‡©‰ , ó¾IŸŠc1 4â&y­&pŠ­6;M À 0¹qç»p.á …ŸÅáK@%6·y6ƒ‰3?”úºŽ‰éX5ªPT §µ!=Mž«Ú½‹ÅgÂSâÉaþÓoö–¯ÁÔìR>5éÿ üs¶ÆUcÌ kÇR ]ÿ ù¬¼«VŽ;Â|‡~¢¦”ÏŰæ {L™Õ°Óv¹ò¸írޡעCÃ!íVÕ {¶»sŒNPg/ "uÕbkm²“$ďå¿é¹§°½æz¯6 †s¿!s–wÚÝ“™Œ °.ûj>·+™Òa…©Œ&rÝÎtÛë긪Ît’LAVp%c Úý[ÄzJ¾ÇàXXç@˜ó<êL]·T˜¾¥1Ó©V‡g´æ½¦Ý@¹óø!_@´ÞâSÁ —S3™•& ]@JHÚý©ZŽ €×æÔr»Áf!‡yÞ4Mv*èÓã_{‘åóUuљØ«Oïé*®EvÑ Œ÷‡U \"㪒ÍK+À 4“M¡ï:0¥5í!'<@î´”>Ç»&Z–ïCCV˜Ì5Šo&îhè.žû |ÓK©h$s6KìŒëã)¹hI¦GïOåóI;ììü#É$Š0…Ææ¥TØ.5­¾gn´ “ÂÖ\:hœ89G)J@„}œ:’Ò{/Š"¦_Æ×7Æ3VÇŠÊa]ÚŒÙ€Ä–=®uÁßâACZƒ§§£ Qnâ:«,×{tyø¬iÛcœÜÄ€H½ÄÍCk´÷šß .W'b¤Íåh]÷€=,Žv×cÚEÚHXJX¶îo¨FÒtèöŸ>ªª6[J®Fµ£sGÁeqõfe\íjÒÐïÄÐGˆe1Ø‹.Ø”‘Ëuø Y­ˆÜ ŽG|zùªüMpDnQWÄ”%JŠ™)â*p@Örš«ÕT2Ð%ˆG#ª„ ·¤!°ŸOTÂT¸aÚ%4&h™LµšØüÐ.F¿²ÐÞ_Ç‚¾ÅÃaÜ÷09Æ q€öy˜v‡85õN÷]¬äѼóS{°_MެúÔ#°Ç¸0åÞè2ëôPcvÆw9®ií1Ä8F™˜à‰´+‰Ik1òÝ7“Ñ×ÒsÝ\x‚h`ÞÑ`ó"|µEcý£n˜h`}GÞ !±ù²Ápü²ß6 0ïi󜵩SÈÇ7˜-ÕURO˜¦´f$ªž-Í6(œ}<„ éc øs]ŽŽ„*—¾ ìdŽ„)méª\¿êÎIg¾ØÞ~I#C/¼¼´EÁÈŽi8“©õådô·>euä ƒ'Ê×लR1ÉJE1ÐAát`t;ÇР%Ý<‡¥„ÍÆ`×Oyó)õiI€ñQaŸ4Ûù\áàaÃÔ¹HÃu¹*k€¦<„e S‡&õÏ B!ŽhüÞ`yj}mªf×\¿ Ç~æ­9‡û\՞Ǖg²1Žû5V7 !àöšm° c`ܬøÇìµÒ'P"?…´Ö,"§^•õލsÔ)6˜sæéÍR¼ ò|Sl”‹7 nPW Gòú÷½§O¯‡„l¡kSÞŒr½PÊ@æ¢pŽ-mÿ #Ÿ˜Àº¶Áä¦;ïÔæ$1££`“Õ>„—·ž)ßð³ñ#Ï Ô$¶œ‰ÊE‹À;÷º ¯«P:Ñ”8–IÊtpÞ3ª“>ê“þës4ò2OÏÕ­±zô†Õ§‰.÷ä¸;¿˜“'œ›žª}«Œ{ª±Ì 9ÔóÞÕ‡0 $íWV3Üì¬ —@kÝ4@¿r¼±½¬™›?øØæ´'Áé®CË3-g$˜ö‡×auÚi´Žp/êÛ æF›Ú2v‹ã¿¿,nB1̨ƃqÞa5͝@&Æû“él÷ \C²½UÍc ¯k×¢U ÖéQå™—-r wô ÞÏ<Ò=&=ÿ Ôê Òêˈt,i—;LîÜ á¸*ÚÃ1$êL•LÍ <É)ýÐà’ ;F™{ƒ™˜€&'}‚ãÄK`¡ÞT@I;®žZóè‚s’7®°›+§O­Åq©é»²9<Ô J ¼9O’HL»Ùïì¸rk¼Ž_ý‘TŸu[²ßÚŒ·ü÷B%¯E ŸÔX5êO´ Ç•€’I0 ÉJX` ñ¹õ%;µŸD‘«´€àwÒ™U ûئžÖö\×®×´8 ½‡ºÐÆÓ§?Àkmœ=;d5*@-ì0F Rªýš[Ü6âö̃ڸr*KA9· u*µæ£?U¸Âêí†8@¦X4 e-ò„0s{ HâUpU?¼mñRa°®a%Ð'tÉ×’\¾ÊÉ]t›h>·(Ë@R¼¡Ãt h}’O÷au<+nT…Ö…MӐ??Óe95 q>í/;&JSû °¯ÊéÞ øƒ*Ã2½Ài&:nôUl=¾¿5eˆ3”ñc|Ú2V”>„»&eE;«ÚäC p¢Û úy 9š[ŒÌx¼擼A&DåÒ¯ˆ¤ÀÌ;"˜ ÏQä¸åhÊ}Ûq«Û0WžÒ|»€ø®öCm5•\ÇÀ§Pe3£]0ÃàLDÉ‰1øªxjgwT‚÷¿LΨK‹›ùs—xˆÜ±µ kæ¸f‰‰ÜGk/LÛØ6d9ò¶ùA{ƒA3š/¬D¬khÓk‰`˜"㯒r¿±Óã jx‡°e}<Ñø\3y:'À•/h½Í€Ç4~g ?Û(¼]v‘ªlKÎâ~?O‚W%{Ì:“'©úNq¾›úo(X’¥¯ˆ nFê{Ç€ü?º'ë ø‹ì Þ09ŒÌç9Æ —ËC`j@ÓÄ(+a‹un¸#ÂꟋ{K`‘ÑÍÍ'à´»/Û,KW;Þ4²þð ï Nm|~fGÏ(…³Ã)«1ö­Õ ¥‡¨©ƒÃ™ü-s=à=U66Ï«Ýc蓦W¹íž®›nÔ%êÇìŒ<#Ü×84ån®Ð ÒåOC` ñânÑs‡¢ç 1õ%Îhì½Ã½® e:ݼUZo™`  ÅZŸŒÊ«ê1ÏÄo$q¹Þ€©ˆhÐÉä¯ñ[!…Ú˜àJ:x2$Íß&PåT£6ç— ‡Í*4Ýšçjÿ ‰É nófÐ ó(L5C•åÆ\rMÒ@ò }y-W}™üýVù—ú¢=Ù”c®‘< M ž ´Phr ¦©TD ‘ù.$´÷O‡‘V2Æò.=IUŒ=ž‡â¬i™aþÓåÙ?òUø'ØÖ•.~* šTŒ!•-×áºTâ®ä#õü'´ eýlYÅÓeÕKÂrT"CÚ@u!Óxƒ{š3€}1¿(r}%«nËamjÑ%ÑNEò v ˜à  σöK³,*º.àzù¨™Ó ÚçâU¦*¿ 9{%Ö¹ njûdaXöb) kÛÆ±ûÓ\°M7ˆÂ=û›ç¿Ã‚­V»Cg–8ÙêE- j)k$º`Ã-ùEýeBÆÇ]c¡°ñty&Òd0nõ'¡W+ƒ*|–øµFa\GQªEAÔp5\Ǽ·¼Ç8·õ -â§Ú[ ‡ uZeÖ 3}×d'+¹:ð+K†Û®s!Ï$úe€<Û”x)1»a­¡LC]¸µík…ÚàA»AYº{†ªS[¦5HÒ7ù --,ísòDØ€èk ÞÀîÜ ò@â( ËNˆë›4ô½•/¦o‡€Û7 ê•ÆêòðÜy'Án½µ á˜ݦ ndeo…[ì¶Ê,¥R³Ä=À±—–ß;£™´ñSâ*g§”ïaið‘Jå~™ÓÞ ß³Õ¢»8x埒²52>AÊb&-÷\7´éÄù€T˜,w;3{ï˜k…à¹ÄqÀ«œ{€\ ˆ¾[´¨јr &Úé„Ívˆ±8†¿]|¬ņ4I×pÞS1ÈÖz‰#Ìv‡G!YNògñ:màTz¢Ý1ô©^O=~ë|5Bã™ç•¼µõ•bÆ@úÕS¬ÈŒ#¬zünrŸ û” Z²•èðV"ÁHÚý©wÝ €7¼Ìu1hÑa3Éä û f$o¿É ™Ú›ÝçnpÒ3äÌ3†Í§,Äï]$‰/pê †«À¼¸e9­Æê_C]žƒ·ý·frÁN«, E=›Çq -‰öŒ:aÏ¿±í&£Í:-} 84‘ÿ eƒQÑeëSsuiA ³g㟥ú£?ÿ ʼn*”“÷aühe:ÊWa@ÒÞk±eØ] F Ô—r.åä˜ @ö¥ªZoÐýYL·¥S²G/‡ñ <~*ZÆ´è>JlòàÛÆ½ÿ 窘ìGN¢:I®KšJp/`íIÁÀõ#Ä-€ö­šµŒoF4|ÆQØÆ@Ì|£Ô…¢À{9˜è½Üó›€ôYÒÎYsið;ís¤€à²ˆ‚4qÉVŒI$ ‰"° æµ8cXGjœˏ¡Aâý•ËÜ¢ûï e·çLx']á"oÅÎê3¯Ç—¹”ó0nå‚âg{Œñ> S´˜îè°g238‚ãköÝfÚd´6Ò€;ò÷±¢™¼›º ¢Æ'¥Ðx'e¬ç ]bÈÆV¢ó‹kýBO ðÊâ$Ÿ!×T 3Mýמ žìٍàÌü‘8÷€àæØ8æ©6‰©L´«…oãpð„~Çk‰!ñ;‹”ÛžÍ àž±z Ÿôû øŸÝužÏ;ÿ #|u6™Þ¬ÚˆÐõA4¶â|ôl|Ê2ŽÇ¤ÝÅÇY.<#Aí.k§hóF‚”Y; M½Ö4hŸ4&›­¿tès´%FìL¥£Ãk‰ÇT¤haÁ¤ÚxfÉ`ÑìË›>i 3t‚:,–+^÷´–{Û–Nxi"x‘Ûg î¨>¥Õ܁ùZH,2Û“:8xÊ¢Çí9.É-Ìâã-=çjwµS˜dütžçwýGòú®®ûº_ˆýx$–¡ãøO EÚÛÏ÷R„×w+3£Á£öUMyR²¹âŒ°š›¸Ñãò9§Ó_Dl+Ùßc›úšGÅÌc†Ž!Ko=¶.‘Îÿ c²(2®V mª.ÿ ¹B›¹å ù„öŸSV>™ü¯$y:G¢Z×àøúdî¹û­·ýÇ´:•c LÍõi_‹ö+ÎæGÊè>OŠ•äž´§Þ{X}¨1ÚTc›»Qþ•êô°t¿OP?eæ~É{5]•ÙR£r5†nZ\ã@ &îJõ ¾àC°þV>fé¥/ü5ñÊIº_é5 ;e­h<@ Ä&æÃëE%;X,ÒãÆÞ`Oò¦kŸm#˜!ÀyÄ¢| óLšò¥Ä` ¶R=|ÈCâh5ò3DˆïF†ðÒ#ÅìÛœ?¸yhBãœí ZxßÎÄhºRK„`Þödvײ™ÀÈÑÒgŒuY w³%†ƒÓzõ ÖÏp‚dH®¦A´ù§»ÓÇMæ~)ˆð‡û:ù&Ä •vGD´À n ݇¼Ö8Fö óáà£~Ë¥x`oK|Ä?fxiØü%pìR>éò+Û±éÎ>núlFŤ'tq8LZÏvÃ?„¡ß±È⽆¯³íü@x|PöUäèØã¡ð‚ŒAìÏ"vÍwóŸÍ{ ý0.z È•Ö{,N¡£¡ŸKÕÙž>Ýœþ ÍÀ°<×EA!Å‚D™IúOÍ¡>ôG}Â` ÍßkÜL™Ž Þð™ {IøF²¹òQ3&!ÃÂÞz.d&Ï-sH¸,Ôõ˜ŽP€ 77ˆÝ¼ÊëÜw =cÕ Ú,ØÐ5ÎYÐ)ì´öœgŒ[¤ßv㙑8心>h]§µháYš£²ºÑ.{Ï7Sð•?´~×SÃKýJÛ˜ ™Íäiúu<µX¶1õ^kâçIÑ£sZ4h>j*ÔšD:4­¿_ ÷¸ Õxæÿ ¸?Mù _•­ÊÐ ä ÷ý ÑwL œ­ïnTkÛUÍN©ë:¦fV ¶ÜÔÜMªÅâA½–¿R×TXš-%iTÊT•‡Ù‚JôϐZxWÑè‰f‰òG º ×Õû2aZ7OU3[“×AT–ÞŒ…-‘¤”Ì ì&(ˆ¿­•ƒkï’:ðY¦W‘ Å)“†‘˜³Åtcø˜ñTÂwÚÇ4|üLÇªí–v- qˆèU qPE.†â‘˜µ Æ,ÐÅs]8¾„oúÑ i>ÜxxÈó)ƒ ´æÁâØ$À‰vžŸf$Ž |ãw;ÀÁIJ»b` {¦Ó¤Ú$©YÀ‘n@Óïž«9J¼êG m¤ ܯ¹ÌW4€ÐÒÅÛ‡#褕Ÿn-?í|с¥÷Ú¹¬'´ÞÜ9ÓK `hê£SÄSà?7—Wí_´…óB›»:=Ãïq`<8ñÓŒÑlú2d¬ê³£hÖ[l|$vÝro~'R®‰§°ñmY ͧäP |PUª¹·:3Œ[Û{Xÿ ºâ@‚W–Äé u‚ ¯´*=íή.pûÒdt @G‰¬ s¸ ëÉücr ÞæÑ¨Ê@>¤¢Ö±. Þ'¯°ÌME[YéïĵÂCå½ Ué©Áû'Ê9%eÔðNU”ë‘ÌsD3/®+UI˜9h.WC”빓$#:pz:YÓ ¿xž* ³$Í +$kñAŠ‹†¢ Uê>¸)_š¬÷©ßAÂÔb9ÇU ¯¾á•9¯ÏÏ÷O÷¼¼Fähal1‰3Ì[Ïr•´UCksNÐ] R‘¸¥H+§Šé†c©vÖÞ0iÓ76s†î!§=ß ¼~Ô'°Ãmäoäš³ªøi1úÉ)³yV8 CLÄØÁ‘WYïi€H6ÖÑiámø^ÈY´°Ñ7¥Û*—Ñ©L«Qƒï—Ùrÿ ›£Ð*š¸ˆL©ˆ$ˆ ÷¾D§9È®«qbqC)–ˆïv´çñsÑVT­Ø, <àïºÀO«Jý·õ àfPìð .wFšir´þ’2_Y *Æ€x\« ì€9š@ Ž|F⇥ˆkZ@hÖÄ0t¿-<“‹qµ¾*ZL¤Ú)&BJpÓF5=$„at*Zš$’ÑtdûÝRI1 2މ$€$I$#‰SÞ’Hë¬ï;Á$¡t$’`<(ñÇt)$‡Ð.Êf¢X’Kt=Éé$‚ˆªè¢oÝëòI%Rgcª÷ŠyI%¡‰ÿ !ñ)´õ $¤ Ô’IIGÿÙ# 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 ._errors import unwrap, APIException from ._types import type_name, byte_cls from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams, RSASSAPSSParams 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 # http://www.secg.org/SEC2-Ver-1.0.pdf '1.2.840.10045.3.1.1': 'secp192r1', '1.2.840.10045.3.1.7': 'secp256r1', '1.3.132.0.1': 'sect163k1', '1.3.132.0.2': 'sect163r1', '1.3.132.0.3': 'sect239k1', '1.3.132.0.4': 'sect113r1', '1.3.132.0.5': 'sect113r2', '1.3.132.0.6': 'secp112r1', '1.3.132.0.7': 'secp112r2', '1.3.132.0.8': 'secp160r1', '1.3.132.0.9': 'secp160k1', '1.3.132.0.10': 'secp256k1', '1.3.132.0.15': 'sect163r2', '1.3.132.0.16': 'sect283k1', '1.3.132.0.17': 'sect283r1', '1.3.132.0.22': 'sect131r1', '1.3.132.0.23': 'sect131r2', '1.3.132.0.24': 'sect193r1', '1.3.132.0.25': 'sect193r2', '1.3.132.0.26': 'sect233k1', '1.3.132.0.27': 'sect233r1', '1.3.132.0.28': 'secp128r1', '1.3.132.0.29': 'secp128r2', '1.3.132.0.30': 'secp160r2', '1.3.132.0.31': 'secp192k1', '1.3.132.0.32': 'secp224k1', '1.3.132.0.33': 'secp224r1', '1.3.132.0.34': 'secp384r1', '1.3.132.0.35': 'secp521r1', '1.3.132.0.36': 'sect409k1', '1.3.132.0.37': 'sect409r1', '1.3.132.0.38': 'sect571k1', '1.3.132.0.39': 'sect571r1', # https://tools.ietf.org/html/rfc5639#section-4.1 '1.3.36.3.3.2.8.1.1.1': 'brainpoolp160r1', '1.3.36.3.3.2.8.1.1.2': 'brainpoolp160t1', '1.3.36.3.3.2.8.1.1.3': 'brainpoolp192r1', '1.3.36.3.3.2.8.1.1.4': 'brainpoolp192t1', '1.3.36.3.3.2.8.1.1.5': 'brainpoolp224r1', '1.3.36.3.3.2.8.1.1.6': 'brainpoolp224t1', '1.3.36.3.3.2.8.1.1.7': 'brainpoolp256r1', '1.3.36.3.3.2.8.1.1.8': 'brainpoolp256t1', '1.3.36.3.3.2.8.1.1.9': 'brainpoolp320r1', '1.3.36.3.3.2.8.1.1.10': 'brainpoolp320t1', '1.3.36.3.3.2.8.1.1.11': 'brainpoolp384r1', '1.3.36.3.3.2.8.1.1.12': 'brainpoolp384t1', '1.3.36.3.3.2.8.1.1.13': 'brainpoolp512r1', '1.3.36.3.3.2.8.1.1.14': 'brainpoolp512t1', } _key_sizes = { # Order values used to compute these sourced from # http://cr.openjdk.java.net/~vinnie/7194075/webrev-3/src/share/classes/sun/security/ec/CurveDB.java.html '1.2.840.10045.3.0.1': 21, '1.2.840.10045.3.0.2': 21, '1.2.840.10045.3.0.3': 21, '1.2.840.10045.3.0.4': 21, '1.2.840.10045.3.0.5': 24, '1.2.840.10045.3.0.6': 24, '1.2.840.10045.3.0.7': 24, '1.2.840.10045.3.0.8': 24, '1.2.840.10045.3.0.9': 24, '1.2.840.10045.3.0.10': 25, '1.2.840.10045.3.0.11': 30, '1.2.840.10045.3.0.12': 30, '1.2.840.10045.3.0.13': 30, '1.2.840.10045.3.0.14': 30, '1.2.840.10045.3.0.15': 30, '1.2.840.10045.3.0.16': 33, '1.2.840.10045.3.0.17': 37, '1.2.840.10045.3.0.18': 45, '1.2.840.10045.3.0.19': 45, '1.2.840.10045.3.0.20': 53, '1.2.840.10045.3.1.2': 24, '1.2.840.10045.3.1.3': 24, '1.2.840.10045.3.1.4': 30, '1.2.840.10045.3.1.5': 30, '1.2.840.10045.3.1.6': 30, # Order values used to compute these sourced from # http://www.secg.org/SEC2-Ver-1.0.pdf # ceil(n.bit_length() / 8) '1.2.840.10045.3.1.1': 24, '1.2.840.10045.3.1.7': 32, '1.3.132.0.1': 21, '1.3.132.0.2': 21, '1.3.132.0.3': 30, '1.3.132.0.4': 15, '1.3.132.0.5': 15, '1.3.132.0.6': 14, '1.3.132.0.7': 14, '1.3.132.0.8': 21, '1.3.132.0.9': 21, '1.3.132.0.10': 32, '1.3.132.0.15': 21, '1.3.132.0.16': 36, '1.3.132.0.17': 36, '1.3.132.0.22': 17, '1.3.132.0.23': 17, '1.3.132.0.24': 25, '1.3.132.0.25': 25, '1.3.132.0.26': 29, '1.3.132.0.27': 30, '1.3.132.0.28': 16, '1.3.132.0.29': 16, '1.3.132.0.30': 21, '1.3.132.0.31': 24, '1.3.132.0.32': 29, '1.3.132.0.33': 28, '1.3.132.0.34': 48, '1.3.132.0.35': 66, '1.3.132.0.36': 51, '1.3.132.0.37': 52, '1.3.132.0.38': 72, '1.3.132.0.39': 72, # Order values used to compute these sourced from # https://tools.ietf.org/html/rfc5639#section-3 # ceil(q.bit_length() / 8) '1.3.36.3.3.2.8.1.1.1': 20, '1.3.36.3.3.2.8.1.1.2': 20, '1.3.36.3.3.2.8.1.1.3': 24, '1.3.36.3.3.2.8.1.1.4': 24, '1.3.36.3.3.2.8.1.1.5': 28, '1.3.36.3.3.2.8.1.1.6': 28, '1.3.36.3.3.2.8.1.1.7': 32, '1.3.36.3.3.2.8.1.1.8': 32, '1.3.36.3.3.2.8.1.1.9': 40, '1.3.36.3.3.2.8.1.1.10': 40, '1.3.36.3.3.2.8.1.1.11': 48, '1.3.36.3.3.2.8.1.1.12': 48, '1.3.36.3.3.2.8.1.1.13': 64, '1.3.36.3.3.2.8.1.1.14': 64, } @classmethod def register(cls, name, oid, key_size): """ Registers a new named elliptic curve that is not included in the default list of named curves :param name: A unicode string of the curve name :param oid: A unicode string of the dotted format OID :param key_size: An integer of the number of bytes the private key should be encoded to """ cls._map[oid] = name if cls._reverse_map is not None: cls._reverse_map[name] = oid cls._key_sizes[oid] = key_size class ECDomainParameters(Choice): """ Source: http://www.secg.org/sec1-v2.pdf page 102 """ _alternatives = [ ('specified', SpecifiedECDomain), ('named', NamedCurve), ('implicit_ca', Null), ] @property def key_size(self): if self.name == 'implicit_ca': raise ValueError(unwrap( ''' Unable to calculate key_size from ECDomainParameters that are implicitly defined by the CA key ''' )) if self.name == 'specified': order = self.chosen['order'].native return math.ceil(math.log(order, 2.0) / 8.0) oid = self.chosen.dotted if oid not in NamedCurve._key_sizes: raise ValueError(unwrap( ''' The asn1crypto.keys.NamedCurve %s does not have a registered key length, please call asn1crypto.keys.NamedCurve.register() ''', repr(oid) )) return NamedCurve._key_sizes[oid] 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}), ] # Ensures the key is set to the correct length when encoding _key_size = None # This is necessary to ensure the private_key IntegerOctetString is encoded properly def __setitem__(self, key, value): res = super(ECPrivateKey, self).__setitem__(key, value) if key == 'private_key': if self._key_size is None: # Infer the key_size from the existing private key if possible pkey_contents = self['private_key'].contents if isinstance(pkey_contents, byte_cls) and len(pkey_contents) > 1: self.set_key_size(len(self['private_key'].contents)) elif self._key_size is not None: self._update_key_size() elif key == 'parameters' and isinstance(self['parameters'], ECDomainParameters) and \ self['parameters'].name != 'implicit_ca': self.set_key_size(self['parameters'].key_size) return res def set_key_size(self, key_size): """ Sets the key_size to ensure the private key is encoded to the proper length :param key_size: An integer byte length to encode the private_key to """ self._key_size = key_size self._update_key_size() def _update_key_size(self): """ Ensure the private_key explicit encoding width is set """ if self._key_size is not None and isinstance(self['private_key'], IntegerOctetString): self['private_key'].set_encoded_width(self._key_size) 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/rfc4055#page-8 '1.2.840.113549.1.1.10': 'rsassa_pss', # 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/rfc8410#section-9 '1.3.101.110': 'x25519', '1.3.101.111': 'x448', '1.3.101.112': 'ed25519', '1.3.101.113': 'ed448', } 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, 'rsassa_pss': RSASSAPSSParams, } 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, 'rsassa_pss': RSAPrivateKey, 'dsa': Integer, 'ec': ECPrivateKey, # These should be treated as opaque octet strings according # to RFC 8410 'x25519': OctetString, 'x448': OctetString, 'ed25519': OctetString, 'ed448': OctetString, }[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' or algorithm == 'rsassa_pss': 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 # This is necessary to ensure any contained ECPrivateKey is the # correct size def __setitem__(self, key, value): res = super(PrivateKeyInfo, self).__setitem__(key, value) algorithm = self['private_key_algorithm'] # When possible, use the parameter info to make sure the private key encoding # retains any necessary leading bytes, instead of them being dropped if (key == 'private_key_algorithm' or key == 'private_key') and \ algorithm['algorithm'].native == 'ec' and \ isinstance(algorithm['parameters'], ECDomainParameters) and \ algorithm['parameters'].name != 'implicit_ca' and \ isinstance(self['private_key'], ParsableOctetString) and \ isinstance(self['private_key'].parsed, ECPrivateKey): self['private_key'].parsed.set_key_size(algorithm['parameters'].key_size) return res def unwrap(self): """ Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or ECPrivateKey object :return: An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object """ raise APIException( 'asn1crypto.keys.PrivateKeyInfo().unwrap() has been removed, ' 'please use oscrypto.asymmetric.PrivateKey().unwrap() instead') @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", "rsassa_pss", "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' or self.algorithm == 'rsassa_pss': 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. """ raise APIException( 'asn1crypto.keys.PrivateKeyInfo().public_key has been removed, ' 'please use oscrypto.asymmetric.PrivateKey().public_key.unwrap() instead') @property def public_key_info(self): """ :return: A PublicKeyInfo object derived from this private key. """ raise APIException( 'asn1crypto.keys.PrivateKeyInfo().public_key_info has been removed, ' 'please use oscrypto.asymmetric.PrivateKey().public_key.asn1 instead') @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) """ raise APIException( 'asn1crypto.keys.PrivateKeyInfo().fingerprint has been removed, ' 'please use oscrypto.asymmetric.PrivateKey().fingerprint instead') 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/rfc4055#page-8 '1.2.840.113549.1.1.10': 'rsassa_pss', # 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', # https://tools.ietf.org/html/rfc8410#section-9 '1.3.101.110': 'x25519', '1.3.101.111': 'x448', '1.3.101.112': 'ed25519', '1.3.101.113': 'ed448', } 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, 'rsassa_pss': RSASSAPSSParams, } 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, 'rsassa_pss': 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, # These should be treated as opaque bit strings according # to RFC 8410, and need not even be valid ASN.1 'x25519': (OctetBitString, None), 'x448': (OctetBitString, None), 'ed25519': (OctetBitString, None), 'ed448': (OctetBitString, None), }[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' and algorithm != 'rsassa_pss': 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 """ raise APIException( 'asn1crypto.keys.PublicKeyInfo().unwrap() has been removed, ' 'please use oscrypto.asymmetric.PublicKey().unwrap() instead') @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", "rsassa_pss", "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 = int(((len(self['public_key'].native) - 1) / 2) * 8) else: if self.algorithm == 'rsa' or self.algorithm == 'rsassa_pss': 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) """ raise APIException( 'asn1crypto.keys.PublicKeyInfo().fingerprint has been removed, ' 'please use oscrypto.asymmetric.PublicKey().fingerprint instead')