| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489 |
- { *********************************************************************************** }
- { * CryptoLib Library * }
- { * Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe * }
- { * Github Repository <https://github.com/Xor-el> * }
- { * Distributed under the MIT software license, see the accompanying file LICENSE * }
- { * or visit http://www.opensource.org/licenses/mit-license.php. * }
- { * Acknowledgements: * }
- { * * }
- { * Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring * }
- { * development of this library * }
- { * ******************************************************************************* * }
- (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
- unit ClpAsn1Objects;
- {$I ..\Include\CryptoLib.inc}
- interface
- uses
- Classes,
- Math,
- SyncObjs,
- StrUtils,
- SysUtils,
- Generics.Collections,
- ClpEncoders,
- ClpBits,
- ClpBigInteger,
- ClpArrayUtils,
- ClpStringUtils,
- ClpCryptoLibTypes,
- ClpConverters,
- ClpIAsn1Objects,
- ClpOidTokenizer,
- ClpIOidTokenizer;
- resourcestring
- SDataOverflow = 'Data Overflow';
- SCorruptedStreamInvalidTag =
- 'Corrupted Stream - Invalid High Tag Number Found';
- SEOFFound = 'EOF Found Inside Tag Value';
- SInvalidEnd = 'EOF Found When Length Expected';
- SInvalidDerLength = 'DER Length More Than 4 Bytes: %d';
- SEndOfStream = 'EOF Found Reading Length';
- SNegativeLength = 'Corrupted Stream - Negative Length Found';
- SOutOfBoundsLength = 'Corrupted stream - Out of Bounds Length Found';
- SUnknownTag = 'Unknown Tag " %d " Encountered';
- SEndOfContent = 'Unexpected End-of-Contents Marker';
- SIndefiniteLength = 'Indefinite Length Primitive Encoding Encountered';
- SUnknownBerObject = 'Unknown BER Object Encountered';
- SCorruptedStream = 'Corrupted Stream Detected: %s';
- SInvalidLength = 'Negative Lengths not Allowed", "Length"';
- SEndOfStreamTwo = 'DEF Length %d " TObject truncated by " %d';
- SInvalidBufferLength = 'Buffer Length Not Right For Data';
- SMalformedContent = 'Malformed End-of-Contents Marker';
- SExtraData = 'Extra Data Found After Object';
- SUnRecognizedObjectStream = 'Cannot Recognise Object in Stream';
- SUnRecognizedObjectByteArray = 'Cannot Recognise Object in ByteArray';
- SIllegalObject = 'Illegal Object in GetInstance: %s, "obj"';
- SStrNil = '"Str" Cannot be Nil';
- SProcessingError = 'Error Processing Object : "%s"';
- SInvalidObject = 'Object Implicit - Explicit Expected.';
- SUnknownObject = 'Unknown object in GetInstance: %s, "obj"';
- SInvalidSequence = 'Failed to Construct Sequence from byte array: "%s"';
- SImplicitObject = 'Implicitly Tagged Object';
- SImplicitTag = 'Implicit Tagging for Tag: %d';
- SUnknownObjectBER = 'Unknown BER Object Encountered: $%x';
- SImplicitTagging = 'Implicit Tagging not Implemented';
- SUnConstructedEncoding =
- 'Sequences Must Use Constructed Encoding (see X.690 8.9.1/8.10.1)';
- SUnConstructedEncoding2 =
- 'Sets Must Use Constructed Encoding (see X.690 8.11.1/8.12.1)';
- SMalformedObject = 'Malformed Object %s';
- SUnSupportedTag = 'Unsupported Tag Number';
- SConvertError = 'EIOCryptoLibException Converting Stream to Byte Array: %s';
- SEncodingError = 'Encoding Error in GetInstance: %s "obj"';
- SDataNil = '"data"';
- SInvalidRange = 'Must be in the Range 0 to 7", "padBits"';
- SPadBitError = 'If "data" is Empty, "padBits" Must be 0';
- SUnalignedData = 'Attempt to Get non-octet Aligned Data from BIT STRING"';
- STruncatedBitString = 'Truncated BIT STRING Detected", "octets"';
- SNotImplemented = 'Not Implemented %s';
- SUnConstructedTag = 'Explicit Tags Must be Constructed (see X.690 8.14.2)';
- SParsingError = '%s';
- SEmptyInput = 'Input Cannot be Empty "astr"';
- SInvalidValue = 'Byte Value Should Have 1 Byte in it'', "val"';
- SInvalidBooleanValue = 'BOOLEAN Value Should Have 1 Byte in it", "Value"';
- SMalformedEnumerated = 'Malformed Enumerated';
- SZeroLength = 'Enumerated has Zero Length, "enc"';
- SInvalidEncoding = 'Invalid Encoding Value: %d';
- SFewObject = 'Too Few Objects in Input Vector, "v"';
- SVectorTooLarge = 'Input Vector too Large", "vector"';
- SNoTaggedObjectFound =
- 'No Tagged Object Found in Vector. Structure Doesn ''t Seem to be of Type External, "Vector"';
- SInvalidEncodingValue = 'Invalid Encoding Value';
- SObjectNil = ' "obj" Can''t be Nil';
- SValueNil = ' "value" Can''t be Nil';
- SMalformedInteger = 'Malformed Integer';
- SIdentifierNil = 'Identifier Cannot be Empty';
- SInvalidOID = '"String " %s is " not an OID"';
- SInvalidBranchId = '"String " %s " not a valid OID branch", "branchID"';
- SIllegalCharacters = 'String Contains Illegal Characters "str"';
- SObjectEncodeError = 'Cannot Encode Object added to SET';
- SIndexOutOfRange = '%d >= %d';
- SInitialCapacityNegative = 'InitialCapacity must not be Negative';
- SElementNil = 'element cannot be Nil';
- SOtherNil = 'other cannot be Nil';
- SOtherElementsNil = 'other elements cannot be Nil';
- SElementsNil = '"elements" cannot be null, or contain null';
- SElementVectorNil = 'elementVector cannot be Nil';
- SASN1IntegerPositiveOutOfRangeError =
- 'ASN.1 Integer out of positive int range';
- SASN1IntegerOutOfRangeError = 'ASN.1 Integer out of int range';
- SEnumeratedNegative = 'enumerated must be non-negative';
- // ** Start Stream Operations ** //
- type
- TStreamHelper = class helper for TStream
- public
- function ReadByte(): Int32;
- procedure WriteByte(b: Byte); inline;
- end;
- type
- TStreamSorter = class sealed(TObject)
- public
- class function Read(input: TStream; var buffer: TCryptoLibByteArray;
- offset, count: Int32): Int32; static;
- class function ReadByte(input: TStream): Int32; static;
- end;
- type
- TStreamUtils = class sealed(TObject)
- strict private
- const
- BufferSize = Int32(512);
- public
- class procedure Drain(const inStr: TStream); static;
- class function ReadAll(const inStr: TStream): TCryptoLibByteArray;
- static; inline;
- class function ReadAllLimited(const inStr: TStream; limit: Int32)
- : TCryptoLibByteArray; static; inline;
- class function ReadFully(const inStr: TStream; var buf: TCryptoLibByteArray)
- : Int32; overload; static; inline;
- class function ReadFully(const inStr: TStream; var buf: TCryptoLibByteArray;
- off, len: Int32): Int32; overload; static;
- class procedure PipeAll(const inStr, outStr: TStream); static;
- /// <summary>
- /// Pipe all bytes from <c>inStr</c> to <c>outStr</c>, throwing <c>
- /// EStreamOverflowCryptoLibException</c> if greater than <c>limit</c> bytes in <c>
- /// inStr</c>.
- /// </summary>
- /// <param name="inStr">
- /// Input Stream
- /// </param>
- /// <param name="limit">
- /// Limit
- /// </param>
- /// <param name="outStr">
- /// Output Stream
- /// </param>
- /// <returns>
- /// The number of bytes actually transferred, if not greater than <c>
- /// limit</c>
- /// </returns>
- /// <exception cref="EStreamOverflowCryptoLibException" />
- class function PipeAllLimited(const inStr: TStream; limit: Int64;
- const outStr: TStream): Int64; static;
- class procedure WriteBufTo(const buf: TMemoryStream; const output: TStream);
- overload; static; inline;
- class function WriteBufTo(const buf: TMemoryStream;
- const output: TCryptoLibByteArray; offset: Int32): Int32; overload;
- static; inline;
- class procedure WriteZeroes(const outStr: TStream; count: Int64); static;
- end;
- type
- TBaseInputStream = class abstract(TStream)
- {$IFDEF DELPHI}
- private
- function GetPosition: Int64; inline;
- procedure SetPosition(const Pos: Int64); inline;
- procedure SetSize64(const NewSize: Int64); inline;
- {$ENDIF DELPHI}
- protected
- {$IFDEF FPC}
- function GetPosition: Int64; override;
- procedure SetPosition(const Pos: Int64); override;
- procedure SetSize64(const NewSize: Int64); override;
- {$ENDIF FPC}
- function GetSize: Int64; override;
- procedure SetSize(NewSize: LongInt); overload; override;
- procedure SetSize(const NewSize: Int64); overload; override;
- public
- function ReadByte: Int32; virtual;
- function Read(var buffer; count: LongInt): LongInt; overload; override;
- function Write(const buffer; count: LongInt): LongInt; overload; override;
- function Read(buffer: TCryptoLibByteArray; offset, count: LongInt)
- : LongInt; overload;
- {$IFDEF SUPPORT_TSTREAM_READ_BYTEARRAY_OVERLOAD} override {$ELSE} virtual
- {$ENDIF SUPPORT_TSTREAM_READ_BYTEARRAY_OVERLOAD};
- function Write(const buffer: TCryptoLibByteArray; offset, count: LongInt)
- : LongInt; overload; {$IFDEF SUPPORT_TSTREAM_WRITE_BYTEARRAY_OVERLOAD} override {$ELSE} virtual
- {$ENDIF SUPPORT_TSTREAM_WRITE_BYTEARRAY_OVERLOAD};
- function Seek(offset: LongInt; Origin: Word): LongInt; overload; override;
- function Seek(const offset: Int64; Origin: TSeekOrigin): Int64;
- overload; override;
- {$IFNDEF _FIXINSIGHT_}
- property Size: Int64 read GetSize write SetSize64;
- {$ENDIF}
- property Position: Int64 read GetPosition write SetPosition;
- end;
- type
- TFilterStream = class(TStream)
- protected
- var
- Fs: TStream;
- function GetPosition: Int64; {$IFDEF FPC} override; {$ENDIF FPC}
- procedure SetPosition(const Value: Int64); {$IFDEF FPC} override;
- {$ENDIF FPC}
- function GetSize: Int64; override;
- public
- constructor Create(const s: TStream);
- property Size: Int64 read GetSize;
- property Position: Int64 read GetPosition write SetPosition;
- function Seek(const offset: Int64; Origin: TSeekOrigin): Int64; override;
- function Read(var buffer; count: LongInt): LongInt; override;
- function Write(const buffer; count: LongInt): LongInt; override;
- function ReadByte(): Int32;
- procedure WriteByte(Value: Byte);
- end;
- type
- TLimitedInputStream = class abstract(TBaseInputStream)
- strict private
- var
- F_limit: Int32;
- strict protected
- var
- F_in: TStream;
- procedure SetParentEofDetect(&on: Boolean);
- public
- constructor Create(inStream: TStream; limit: Int32);
- function GetRemaining(): Int32; virtual;
- end;
- type
- TDefiniteLengthInputStream = class(TLimitedInputStream)
- strict private
- var
- F_originalLength, F_remaining: Int32;
- function GetRemaining: Int32; reintroduce; inline;
- class function GetEmptyBytes: TCryptoLibByteArray; static; inline;
- public
- constructor Create(inStream: TStream; length: Int32);
- function ReadByte(): Int32; override;
- function Read(buf: TCryptoLibByteArray; off, len: LongInt)
- : LongInt; override;
- procedure ReadAllIntoByteArray(var buf: TCryptoLibByteArray);
- function ToArray: TCryptoLibByteArray;
- property Remaining: Int32 read GetRemaining;
- class property EmptyBytes: TCryptoLibByteArray read GetEmptyBytes;
- end;
- type
- /// <summary>
- /// a general purpose ASN.1 decoder - note: this class differs from the <br />
- /// others in that it returns null after it has read the last object in <br />
- /// the stream. If an ASN.1 Null is encountered a DerBER Null object is <br />
- /// returned. <br />
- /// </summary>
- TAsn1InputStream = class(TFilterStream)
- strict private
- var
- Flimit: Int32;
- FtmpBuffers: TCryptoLibMatrixByteArray;
- FStream: TStream;
- /// <summary>
- /// build an object given its tag and the number of bytes to construct it
- /// from.
- /// </summary>
- function BuildObject(tag, tagNo, length: Int32): IAsn1Object;
- public
- constructor Create(const inputStream: TStream); overload;
- /// <summary>
- /// Create an ASN1InputStream where no DER object will be longer than
- /// limit.
- /// </summary>
- /// <param name="inputStream">
- /// stream containing ASN.1 encoded data.
- /// </param>
- /// <param name="limit">
- /// maximum size of a DER encoded object.
- /// </param>
- constructor Create(const inputStream: TStream; limit: Int32); overload;
- destructor Destroy(); override;
- /// <summary>
- /// the stream is automatically limited to the length of the input array.
- /// </summary>
- /// <param name="input">
- /// array containing ASN.1 encoded data.
- /// </param>
- constructor Create(const input: TCryptoLibByteArray); overload;
- function ReadObject(): IAsn1Object;
- function ReadVector(const dIn: TDefiniteLengthInputStream)
- : IAsn1EncodableVector; virtual;
- function CreateDerSequence(const dIn: TDefiniteLengthInputStream)
- : IDerSequence; virtual;
- function CreateDerSet(const dIn: TDefiniteLengthInputStream)
- : IDerSet; virtual;
- class function FindLimit(const input: TStream): Int32; static;
- class function ReadTagNumber(const s: TStream; tag: Int32): Int32; static;
- class function ReadLength(const s: TStream; limit: Int32): Int32; static;
- class function GetBuffer(const defIn: TDefiniteLengthInputStream;
- const tmpBuffers: TCryptoLibMatrixByteArray): TCryptoLibByteArray;
- static; inline;
- class function CreatePrimitiveDerObject(tagNo: Int32;
- const defIn: TDefiniteLengthInputStream;
- const tmpBuffers: TCryptoLibMatrixByteArray): IAsn1Object; static;
- end;
- type
- TDerOutputStream = class(TFilterStream)
- strict private
- procedure WriteLength(length: Int32);
- strict protected
- procedure WriteNull();
- public
- constructor Create(const os: TStream);
- procedure WriteEncoded(tag: Int32;
- const bytes: TCryptoLibByteArray); overload;
- procedure WriteEncoded(tag: Int32; first: Byte;
- const bytes: TCryptoLibByteArray); overload;
- procedure WriteEncoded(tag: Int32; const bytes: TCryptoLibByteArray;
- offset, length: Int32); overload;
- procedure WriteEncoded(flags, tagNo: Int32;
- const bytes: TCryptoLibByteArray); overload;
- procedure WriteTag(flags, tagNo: Int32);
- procedure WriteObject(const obj: IAsn1Encodable); overload; virtual;
- procedure WriteObject(const obj: IAsn1Object); overload; virtual;
- end;
- type
- TAsn1OutputStream = class sealed(TDerOutputStream)
- public
- constructor Create(os: TStream);
- end;
- type
- // TODO Make Obsolete in favour of Asn1OutputStream?
- TBerOutputStream = class sealed(TDerOutputStream)
- public
- constructor Create(os: TStream);
- end;
- type
- TConstructedOctetStream = class(TBaseInputStream)
- strict private
- var
- F_parser: IAsn1StreamParser;
- F_first: Boolean;
- F_currentStream: TStream;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function Read(buffer: TCryptoLibByteArray; offset, count: LongInt)
- : LongInt; override;
- function ReadByte(): Int32; override;
- end;
- type
- TIndefiniteLengthInputStream = class(TLimitedInputStream)
- strict private
- var
- F_lookAhead: Int32;
- F_eofOn00: Boolean;
- function CheckForEof(): Boolean; inline;
- function RequireByte(): Int32; inline;
- public
- constructor Create(inStream: TStream; limit: Int32);
- procedure SetEofOn00(eofOn00: Boolean);
- function Read(buffer: TCryptoLibByteArray; offset, count: LongInt)
- : LongInt; override;
- function ReadByte(): Int32; override;
- end;
- // ** End Stream Operations ** //
- type
- TCollectionUtilities = class sealed(TObject)
- public
- class function ToStructuredString(c: TCryptoLibGenericArray<IAsn1Encodable>)
- : String; static;
- end;
- type
- TAsn1Encodable = class abstract(TInterfacedObject, IAsn1Encodable,
- IAsn1Convertible)
- public
- const
- Der: String = 'DER';
- Ber: String = 'BER';
- function GetEncoded(): TCryptoLibByteArray; overload;
- function GetEncoded(const encoding: String): TCryptoLibByteArray; overload;
- /// <summary>
- /// Return the DER encoding of the object, null if the DER encoding can
- /// not be made.
- /// </summary>
- /// <returns>
- /// return a DER byte array, null otherwise.
- /// </returns>
- function GetDerEncoded(): TCryptoLibByteArray; overload;
- function Equals(const other: IAsn1Convertible): Boolean; reintroduce;
- function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
- {$ENDIF DELPHI}override;
- function ToAsn1Object(): IAsn1Object; virtual; abstract;
- class function IsNullOrContainsNull(const data
- : TCryptoLibGenericArray<IAsn1Encodable>): Boolean; static;
- class function OpenArrayToDynamicArray(const data: array of IAsn1Encodable)
- : TCryptoLibGenericArray<IAsn1Encodable>; static;
- end;
- type
- TAsn1Object = class abstract(TAsn1Encodable, IAsn1Object)
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- virtual; abstract;
- function Asn1GetHashCode(): Int32; virtual; abstract;
- public
- /// <summary>Create a base ASN.1 object from a byte array.</summary>
- /// <param name="data">The byte array to parse.</param>
- /// <returns>The base ASN.1 object represented by the byte array.</returns>
- /// <exception cref="IOException">
- /// If there is a problem parsing the data, or parsing an object did not exhaust the available data.
- /// </exception>
- class function FromByteArray(const data: TCryptoLibByteArray)
- : IAsn1Object; static;
- /// <summary>Read a base ASN.1 object from a stream.</summary>
- /// <param name="inStr">The stream to parse.</param>
- /// <returns>The base ASN.1 object represented by the byte array.</returns>
- /// <exception cref="IOException">If there is a problem parsing the data.</exception>
- class function FromStream(const inStr: TStream): IAsn1Object; static;
- function ToAsn1Object(): IAsn1Object; override;
- procedure Encode(const derOut: TStream); virtual; abstract;
- function CallAsn1Equals(const obj: IAsn1Object): Boolean;
- function CallAsn1GetHashCode(): Int32;
- end;
- type
- TDerObjectIdentifier = class(TAsn1Object, IDerObjectIdentifier)
- strict private
- const
- LONG_LIMIT = Int64((Int64($7FFFFFFFFFFFFFFF) shr 7) - $7F);
- class var
- FLock: TCriticalSection;
- Fcache: array [0 .. 1023] of IDerObjectIdentifier;
- var
- Fidentifier: String;
- Fbody: TCryptoLibByteArray;
- class procedure Boot(); static;
- class constructor CreateDerObjectIdentifier();
- class destructor DestroyDerObjectIdentifier();
- constructor Create(const oid: IDerObjectIdentifier;
- const branchID: String); overload;
- constructor Create(const bytes: TCryptoLibByteArray); overload;
- function GetID: String; inline;
- procedure WriteField(const outputStream: TStream;
- fieldValue: Int64); overload;
- procedure WriteField(const outputStream: TStream;
- const fieldValue: TBigInteger); overload;
- procedure DoOutput(const bOut: TMemoryStream); overload;
- function GetBody(): TCryptoLibByteArray;
- class function IsValidBranchID(const branchID: String; start: Int32)
- : Boolean; static;
- class function IsValidIdentifier(const identifier: String): Boolean; static;
- class function MakeOidStringFromBytes(const bytes: TCryptoLibByteArray)
- : String; static;
- strict protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- // /**
- // * return an Oid from the passed in object
- // *
- // * @exception ArgumentException if the object cannot be converted.
- // */
- class function GetInstance(const obj: TObject): IDerObjectIdentifier;
- overload; static;
- // /**
- // * return an Oid from the passed in byte array
- // */
- class function GetInstance(const obj: TCryptoLibByteArray)
- : IDerObjectIdentifier; overload; static; inline;
- // /**
- // * return an object Identifier from a tagged object.
- // *
- // * @param obj the tagged object holding the object we want
- // * @param explicitly true if the object is meant to be explicitly
- // * tagged false otherwise.
- // * @exception ArgumentException if the tagged object cannot
- // * be converted.
- // */
- class function GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IDerObjectIdentifier; overload; static; inline;
- class function FromOctetString(const enc: TCryptoLibByteArray)
- : IDerObjectIdentifier; static;
- constructor Create(const identifier: String); overload;
- property ID: String read GetID;
- function Branch(const branchID: String): IDerObjectIdentifier; virtual;
- // /**
- // * Return true if this oid is an extension of the passed in branch, stem.
- // * @param stem the arc or branch that is a possible parent.
- // * @return true if the branch is on the passed in stem, false otherwise.
- // */
- function &on(const stem: IDerObjectIdentifier): Boolean; virtual;
- procedure Encode(const derOut: TStream); override;
- function ToString(): String; override;
- end;
- type
- /// <summary>
- /// Mutable class for building ASN.1 constructed objects such as SETs or
- /// SEQUENCEs.
- /// </summary>
- TAsn1EncodableVector = class sealed(TInterfacedObject, IAsn1EncodableVector)
- strict private
- const
- DefaultCapacity = Int32(10);
- var
- FElements: TCryptoLibGenericArray<IAsn1Encodable>;
- FElementCount: Int32;
- FCopyOnWrite: Boolean;
- function GetCount: Int32;
- function GetSelf(Index: Int32): IAsn1Encodable;
- procedure Reallocate(minCapacity: Int32);
- class function GetEmptyElements: TCryptoLibGenericArray<IAsn1Encodable>;
- static; inline;
- public
- class function FromEnumerable(const e: TList<IAsn1Encodable>)
- : IAsn1EncodableVector; static;
- constructor Create(); overload;
- constructor Create(initialCapacity: Int32); overload;
- constructor Create(const v: array of IAsn1Encodable); overload;
- destructor Destroy(); override;
- procedure Add(const objs: array of IAsn1Encodable); overload;
- procedure Add(const element: IAsn1Encodable); overload;
- procedure AddAll(const other: IAsn1EncodableVector);
- procedure AddOptional(const objs: array of IAsn1Encodable);
- procedure AddOptionalTagged(isExplicit: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable);
- property Self[Index: Int32]: IAsn1Encodable read GetSelf; default;
- property count: Int32 read GetCount;
- function GetEnumerable: TCryptoLibGenericArray<IAsn1Encodable>; virtual;
- function CopyElements(): TCryptoLibGenericArray<IAsn1Encodable>;
- function TakeElements(): TCryptoLibGenericArray<IAsn1Encodable>;
- class function CloneElements(const elements
- : TCryptoLibGenericArray<IAsn1Encodable>)
- : TCryptoLibGenericArray<IAsn1Encodable>; static;
- class property EmptyElements: TCryptoLibGenericArray<IAsn1Encodable>
- read GetEmptyElements;
- end;
- type
- TAsn1Generator = class abstract(TInterfacedObject, IAsn1Generator)
- strict private
- var
- F_out: TStream;
- strict protected
- constructor Create(outStream: TStream);
- function GetOut: TStream; inline;
- property &Out: TStream read GetOut;
- public
- procedure AddObject(const obj: IAsn1Encodable); virtual; abstract;
- function GetRawOutputStream(): TStream; virtual; abstract;
- procedure Close(); virtual; abstract;
- end;
- type
- /// <summary>
- /// A Null object.
- /// </summary>
- TAsn1Null = class abstract(TAsn1Object, IAsn1Null)
- public
- function ToString(): String; override;
- end;
- type
- TAsn1OctetString = class abstract(TAsn1Object, IAsn1OctetString,
- IAsn1OctetStringParser)
- strict private
- var
- FStr: TCryptoLibByteArray;
- strict protected
- function GetStr: TCryptoLibByteArray; inline;
- function GetParser: IAsn1OctetStringParser; inline;
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- property Str: TCryptoLibByteArray read GetStr;
- property parser: IAsn1OctetStringParser read GetParser;
- /// <summary>
- /// return an Octet string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want.
- /// </param>
- /// <param name="isExplicit">
- /// explicitly true if the object is meant to be explicitly tagged false
- /// otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IAsn1OctetString; overload; static;
- /// <summary>
- /// return an Octet string from the given object.
- /// </summary>
- /// <param name="obj">
- /// the object we want converted.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IAsn1OctetString;
- overload; static;
- /// <param name="Str">
- /// the octets making up the octet string.
- /// </param>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- constructor Create(const obj: IAsn1Encodable); overload;
- function GetOctetStream(): TStream;
- function GetOctets(): TCryptoLibByteArray; virtual;
- function ToString(): String; override;
- end;
- type
- /// <summary>
- /// return an Asn1Sequence from the given object.
- /// </summary>
- TAsn1Sequence = class abstract(TAsn1Object, IAsn1Sequence)
- strict private
- var
- FElements: TCryptoLibGenericArray<IAsn1Encodable>;
- type
- TAsn1SequenceParserImpl = class sealed(TInterfacedObject,
- IAsn1SequenceParserImpl, IAsn1SequenceParser)
- strict private
- var
- Fouter: IAsn1Sequence;
- Fmax, Findex: Int32;
- public
- constructor Create(const outer: IAsn1Sequence);
- function ReadObject(): IAsn1Convertible;
- function ToAsn1Object(): IAsn1Object;
- end;
- strict protected
- function GetCount: Int32; virtual;
- function GetParser: IAsn1SequenceParser; virtual;
- function GetSelf(Index: Int32): IAsn1Encodable; virtual;
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function GetElements: TCryptoLibGenericArray<IAsn1Encodable>; inline;
- constructor Create(); overload;
- constructor Create(const element: IAsn1Encodable); overload;
- constructor Create(const elements: array of IAsn1Encodable); overload;
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- public
- destructor Destroy(); override;
- function ToString(): String; override;
- function GetEnumerable: TCryptoLibGenericArray<IAsn1Encodable>; virtual;
- function ToArray(): TCryptoLibGenericArray<IAsn1Encodable>; virtual;
- // /**
- // * return the object at the sequence position indicated by index.
- // *
- // * @param index the sequence number (starting at zero) of the object
- // * @return the object at the sequence position indicated by index.
- // */
- property Self[Index: Int32]: IAsn1Encodable read GetSelf; default;
- /// <summary>
- /// return an Asn1Sequence from the given object.
- /// </summary>
- /// <param name="obj">
- /// the object we want converted.
- /// </param>
- /// <exception cref="EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IAsn1Sequence;
- overload; static;
- /// <summary>
- /// return an Asn1Sequence from the given object.
- /// </summary>
- /// <param name="obj">
- /// the byte array we want converted.
- /// </param>
- /// <exception cref="EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TCryptoLibByteArray): IAsn1Sequence;
- overload; static;
- // /**
- // * Return an ASN1 sequence from a tagged object. There is a special
- // * case here, if an object appears to have been explicitly tagged on
- // * reading but we were expecting it to be implicitly tagged in the
- // * normal course of events it indicates that we lost the surrounding
- // * sequence - so we need to add it back (this will happen if the tagged
- // * object is a sequence that contains other sequences). If you are
- // * dealing with implicitly tagged sequences you really <b>should</b>
- // * be using this method.
- // *
- // * @param obj the tagged object.
- // * @param explicitly true if the object is meant to be explicitly tagged,
- // * false otherwise.
- // * @exception ArgumentException if the tagged object cannot
- // * be converted.
- // */
- class function GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1Sequence; overload; static;
- property parser: IAsn1SequenceParser read GetParser;
- property count: Int32 read GetCount;
- property elements: TCryptoLibGenericArray<IAsn1Encodable> read GetElements;
- end;
- type
- TDerOctetString = class(TAsn1OctetString, IDerOctetString)
- public
- /// <param name="str">The octets making up the octet string.</param>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- constructor Create(const obj: IAsn1Encodable); overload;
- destructor Destroy(); override;
- procedure Encode(const derOut: TStream); overload; override;
- class procedure Encode(const derOut: TDerOutputStream;
- const bytes: TCryptoLibByteArray; offset, length: Int32); reintroduce;
- overload; static; inline;
- end;
- type
- TBerOctetString = class(TDerOctetString, IBerOctetString)
- strict private
- const
- MaxLength = Int32(1000);
- var
- Focts: TList<IDerOctetString>;
- function GenerateOcts(): TList<IDerOctetString>;
- class function ToBytes(octs: TList<IDerOctetString>)
- : TCryptoLibByteArray; static;
- public
- /// <inheritdoc />
- /// <param name="str">The octets making up the octet string.</param>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- constructor Create(const octets: TList<IDerOctetString>); overload;
- constructor Create(const obj: IAsn1Object); overload;
- constructor Create(const obj: IAsn1Encodable); overload;
- destructor Destroy(); override;
- function GetOctets(): TCryptoLibByteArray; override;
- /// <summary>
- /// return the DER octets that make up this string.
- /// </summary>
- function GetEnumerable: TCryptoLibGenericArray<IDerOctetString>; virtual;
- procedure Encode(const derOut: TStream); override;
- class function FromSequence(const seq: IAsn1Sequence)
- : IBerOctetString; static;
- end;
- type
- /// <summary>
- /// A Null object.
- /// </summary>
- TDerNull = class(TAsn1Null, IDerNull)
- strict private
- class function GetInstance: IDerNull; static; inline;
- const
- ZeroBytes: TCryptoLibByteArray = Nil;
- strict protected
- constructor Create(dummy: Int32);
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function Asn1GetHashCode(): Int32; override;
- public
- procedure Encode(const derOut: TStream); override;
- class property Instance: IDerNull read GetInstance;
- end;
- type
- TDerSequence = class(TAsn1Sequence, IDerSequence)
- strict private
- class function GetEmpty: IDerSequence; static; inline;
- public
- class function FromVector(const elementVector: IAsn1EncodableVector)
- : IDerSequence; static;
- /// <summary>
- /// create an empty sequence
- /// </summary>
- constructor Create(); overload;
- /// <summary>
- /// create a sequence containing one object
- /// </summary>
- constructor Create(const element: IAsn1Encodable); overload;
- constructor Create(const elements: array of IAsn1Encodable); overload;
- /// <summary>
- /// create a sequence containing a vector of objects.
- /// </summary>
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- destructor Destroy(); override;
- /// <summary>
- /// A note on the implementation: <br />As Der requires the constructed,
- /// definite-length model to <br />be used for structured types, this
- /// varies slightly from the <br />ASN.1 descriptions given. Rather than
- /// just outputing Sequence, <br />we also have to specify Constructed,
- /// and the objects length. <br />
- /// </summary>
- procedure Encode(const derOut: TStream); override;
- class property Empty: IDerSequence read GetEmpty;
- end;
- type
- TBerSequence = class(TDerSequence, IBerSequence)
- strict private
- class function GetEmpty: IBerSequence; static; inline;
- public
- class function FromVector(const elementVector: IAsn1EncodableVector)
- : IBerSequence; static;
- /// <summary>
- /// create an empty sequence
- /// </summary>
- constructor Create(); overload;
- /// <summary>
- /// create a sequence containing one object
- /// </summary>
- constructor Create(const element: IAsn1Encodable); overload;
- constructor Create(const elements: array of IAsn1Encodable); overload;
- /// <summary>
- /// create a sequence containing a vector of objects.
- /// </summary>
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- destructor Destroy(); override;
- /// <summary>
- /// A note on the implementation: <br />As Der requires the constructed,
- /// definite-length model to <br />be used for structured types, this
- /// varies slightly from the <br />ASN.1 descriptions given. Rather than
- /// just outputing Sequence, <br />we also have to specify Constructed,
- /// and the objects length. <br />
- /// </summary>
- procedure Encode(const derOut: TStream); override;
- class property Empty: IBerSequence read GetEmpty;
- end;
- type
- /// **
- // * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
- // * a [n] where n is some number - these are assumed to follow the construction
- // * rules (as with sequences).
- // */
- TAsn1TaggedObject = class abstract(TAsn1Object, IAsn1TaggedObject,
- IAsn1TaggedObjectParser)
- strict private
- FtagNo: Int32;
- Fexplicitly: Boolean;
- Fobj: IAsn1Encodable;
- strict protected
- // /**
- // * @param tagNo the tag number for this object.
- // * @param obj the tagged object.
- // */
- constructor Create(tagNo: Int32; const obj: IAsn1Encodable); overload;
- // /**
- // * @param explicitly true if the object is explicitly tagged.
- // * @param tagNo the tag number for this object.
- // * @param obj the tagged object.
- // */
- constructor Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable); overload;
- function GetTagNo: Int32; inline;
- function Getexplicitly: Boolean; inline;
- function Getobj: IAsn1Encodable; inline;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function Asn1GetHashCode(): Int32; override;
- public
- class function IsConstructed(isExplicit: Boolean; const obj: IAsn1Object)
- : Boolean; static;
- class function GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1TaggedObject; overload; static; inline;
- class function GetInstance(obj: TObject): IAsn1TaggedObject; overload;
- static; inline;
- property tagNo: Int32 read GetTagNo;
- property explicitly: Boolean read Getexplicitly;
- property obj: IAsn1Encodable read Getobj;
- // /**
- // * return whether or not the object may be explicitly tagged.
- // * <p>
- // * Note: if the object has been read from an input stream, the only
- // * time you can be sure if isExplicit is returning the true state of
- // * affairs is if it returns false. An implicitly tagged object may appear
- // * to be explicitly tagged, so you need to understand the context under
- // * which the reading was done as well, see GetObject below.</p>
- // */
- function isExplicit(): Boolean; inline;
- function IsEmpty(): Boolean; inline;
- // /**
- // * return whatever was following the tag.
- // * <p>
- // * Note: tagged objects are generally context dependent if you're
- // * trying to extract a tagged object you should be going via the
- // * appropriate GetInstance method.</p>
- // */
- function GetObject(): IAsn1Object; inline;
- // /**
- // * Return the object held in this tagged object as a parser assuming it has
- // * the type of the passed in tag. If the object doesn't have a parser
- // * associated with it, the base object is returned.
- // */
- function GetObjectParser(tag: Int32; isExplicit: Boolean): IAsn1Convertible;
- function ToString(): String; override;
- end;
- type
- TAsn1Tags = class sealed(TObject)
- public
- const
- &Boolean = Int32($01);
- &Integer = Int32($02);
- BitString = Int32($03);
- OctetString = Int32($04);
- Null = Int32($05);
- ObjectIdentifier = Int32($06);
- &External = Int32($08);
- Enumerated = Int32($0A);
- Sequence = Int32($10);
- SequenceOf = Int32($10); // for completeness
- &Set = Int32($11);
- SetOf = Int32($11); // for completeness
- NumericString = Int32($12);
- PrintableString = Int32($13);
- T61String = Int32($14);
- VideotexString = Int32($15);
- IA5String = Int32($16);
- UtcTime = Int32($17);
- GeneralizedTime = Int32($18);
- GraphicString = Int32($19);
- VisibleString = Int32($1A);
- GeneralString = Int32($1B);
- UniversalString = Int32($1C);
- BmpString = Int32($1E);
- Utf8String = Int32($0C);
- Constructed = Int32($20);
- Application = Int32($40);
- Tagged = Int32($80);
- end;
- type
- /// <summary>
- /// return an Asn1Set from the given object.
- /// </summary>
- TAsn1Set = class abstract(TAsn1Object, IAsn1Set)
- strict private
- var
- FElements: TCryptoLibGenericArray<IAsn1Encodable>;
- function GetDerEncoded(const obj: IAsn1Encodable)
- : TCryptoLibByteArray; overload;
- /// <summary>
- /// return true if a <= b (arrays are assumed padded with zeros).
- /// </summary>
- class function LessThanOrEqual(const a, b: TCryptoLibByteArray)
- : Boolean; static;
- type
- TAsn1SetParserImpl = class sealed(TInterfacedObject, IAsn1SetParserImpl,
- IAsn1SetParser)
- strict private
- Fouter: IAsn1Set;
- Fmax, Findex: Int32;
- public
- constructor Create(const outer: IAsn1Set);
- function ReadObject(): IAsn1Convertible;
- function ToAsn1Object(): IAsn1Object;
- end;
- strict protected
- function GetCount: Int32; virtual;
- function GetParser: IAsn1SetParser; inline;
- function GetSelf(Index: Int32): IAsn1Encodable; virtual;
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function GetElements: TCryptoLibGenericArray<IAsn1Encodable>; inline;
- procedure Sort();
- constructor Create(); overload;
- constructor Create(const element: IAsn1Encodable); overload;
- constructor Create(const elements: array of IAsn1Encodable); overload;
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- public
- destructor Destroy(); override;
- function ToString(): String; override;
- function ToArray(): TCryptoLibGenericArray<IAsn1Encodable>; virtual;
- function GetEnumerable: TCryptoLibGenericArray<IAsn1Encodable>; virtual;
- // /**
- // * return the object at the sequence position indicated by index.
- // *
- // * @param index the sequence number (starting at zero) of the object
- // * @return the object at the sequence position indicated by index.
- // */
- property Self[Index: Int32]: IAsn1Encodable read GetSelf; default;
- /// <summary>
- /// return an ASN1Set from the given object.
- /// </summary>
- /// <param name="obj">
- /// the object we want converted.
- /// </param>
- /// <exception cref="EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IAsn1Set; overload; static;
- /// <summary>
- /// return an Asn1Set from the given object.
- /// </summary>
- /// <param name="obj">
- /// the byte array we want converted.
- /// </param>
- /// <exception cref="EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TCryptoLibByteArray): IAsn1Set;
- overload; static;
- // /**
- // * Return an ASN1 sequence from a tagged object. There is a special
- // * case here, if an object appears to have been explicitly tagged on
- // * reading but we were expecting it to be implicitly tagged in the
- // * normal course of events it indicates that we lost the surrounding
- // * sequence - so we need to add it back (this will happen if the tagged
- // * object is a sequence that contains other sequences). If you are
- // * dealing with implicitly tagged sequences you really <b>should</b>
- // * be using this method.
- // *
- // * @param obj the tagged object.
- // * @param explicitly true if the object is meant to be explicitly tagged,
- // * false otherwise.
- // * @exception ArgumentException if the tagged object cannot
- // * be converted.
- // */
- class function GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1Set; overload; static;
- property parser: IAsn1SetParser read GetParser;
- property count: Int32 read GetCount;
- property elements: TCryptoLibGenericArray<IAsn1Encodable> read GetElements;
- end;
- type
- /// <summary>
- /// A Der encoded set object
- /// </summary>
- TDerSet = class(TAsn1Set, IDerSet)
- strict private
- class function GetEmpty: IDerSet; static; inline;
- public
- class function FromVector(const elementVector: IAsn1EncodableVector)
- : IDerSet; overload; static;
- class function FromVector(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean): IDerSet; overload; static;
- /// <summary>
- /// create an empty set
- /// </summary>
- constructor Create(); overload;
- /// <param name="element">
- /// a single object that makes up the set.
- /// </param>
- constructor Create(const element: IAsn1Encodable); overload;
- constructor Create(const elements: array of IAsn1Encodable); overload;
- /// <param name="elementVector">
- /// a vector of objects making up the set.
- /// </param>
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- constructor Create(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean); overload;
- destructor Destroy(); override;
- /// <summary>
- /// A note on the implementation: <br />As Der requires the constructed,
- /// definite-length model to <br />be used for structured types, this
- /// varies slightly from the <br />ASN.1 descriptions given. Rather than
- /// just outputing Set, <br />we also have to specify Constructed, and
- /// the objects length. <br />
- /// </summary>
- procedure Encode(const derOut: TStream); override;
- class property Empty: IDerSet read GetEmpty;
- end;
- type
- TAsn1StreamParser = class(TInterfacedObject, IAsn1StreamParser)
- strict private
- var
- F_in: TStream;
- F_limit: Int32;
- FtmpBuffers: TCryptoLibMatrixByteArray;
- procedure Set00Check(enabled: Boolean); inline;
- public
- constructor Create(const inStream: TStream); overload;
- constructor Create(const inStream: TStream; limit: Int32); overload;
- constructor Create(const encoding: TCryptoLibByteArray); overload;
- destructor Destroy; override;
- function ReadIndef(tagValue: Int32): IAsn1Convertible;
- function ReadImplicit(Constructed: Boolean; tag: Int32): IAsn1Convertible;
- function ReadTaggedObject(Constructed: Boolean; tag: Int32): IAsn1Object;
- function ReadObject(): IAsn1Convertible; virtual;
- function ReadVector(): IAsn1EncodableVector; inline;
- end;
- type
- TDerSetParser = class(TInterfacedObject, IAsn1SetParser, IAsn1Convertible,
- IDerSetParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; inline;
- end;
- type
- TDerSequenceParser = class(TInterfacedObject, IAsn1SequenceParser,
- IAsn1Convertible, IDerSequenceParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; inline;
- end;
- type
- /// <summary>
- /// Base class for an application specific object
- /// </summary>
- TDerApplicationSpecific = class(TAsn1Object, IDerApplicationSpecific)
- strict private
- var
- FisConstructed: Boolean;
- Ftag: Int32;
- Foctets: TCryptoLibByteArray;
- class function ReplaceTagNumber(newTag: Int32;
- const input: TCryptoLibByteArray): TCryptoLibByteArray; static;
- strict protected
- function GetApplicationTag: Int32; inline;
- function GetLengthOfHeader(const data: TCryptoLibByteArray): Int32; inline;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function Asn1GetHashCode(): Int32; override;
- public
- constructor Create(IsConstructed: Boolean; tag: Int32;
- const octets: TCryptoLibByteArray); overload;
- constructor Create(tag: Int32; const octets: TCryptoLibByteArray); overload;
- constructor Create(tag: Int32; const obj: IAsn1Encodable); overload;
- constructor Create(isExplicit: Boolean; tag: Int32;
- const obj: IAsn1Encodable); overload;
- constructor Create(tagNo: Int32; const vec: IAsn1EncodableVector); overload;
- function IsConstructed(): Boolean; inline;
- function GetContents(): TCryptoLibByteArray; inline;
- /// <summary>
- /// Return the enclosed object assuming explicit tagging.
- /// </summary>
- /// <returns>
- /// the resulting object
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EIOCryptoLibException">
- /// if reconstruction fails.
- /// </exception>
- function GetObject(): IAsn1Object; overload; inline;
- /// <summary>
- /// Return the enclosed object assuming implicit tagging.
- /// </summary>
- /// <param name="derTagNo">
- /// the type tag that should be applied to the object's contents.
- /// </param>
- /// <returns>
- /// the resulting object
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EIOCryptoLibException">
- /// if reconstruction fails.
- /// </exception>
- function GetObject(derTagNo: Int32): IAsn1Object; overload; inline;
- procedure Encode(const derOut: TStream); override;
- property ApplicationTag: Int32 read GetApplicationTag;
- end;
- type
- TBerApplicationSpecific = class(TDerApplicationSpecific,
- IBerApplicationSpecific)
- public
- constructor Create(tagNo: Int32; const vec: IAsn1EncodableVector);
- end;
- type
- TBerOctetStringParser = class(TInterfacedObject, IAsn1OctetStringParser,
- IAsn1Convertible, IBerOctetStringParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function GetOctetStream(): TStream; inline;
- function ToAsn1Object(): IAsn1Object;
- end;
- type
- TBerApplicationSpecificParser = class(TInterfacedObject,
- IAsn1ApplicationSpecificParser, IAsn1Convertible,
- IBerApplicationSpecificParser)
- strict private
- var
- F_tag: Int32;
- F_parser: IAsn1StreamParser;
- public
- constructor Create(tag: Int32; const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; inline;
- end;
- type
- TDerStringBase = class abstract(TAsn1Object, IAsn1String, IDerStringBase)
- strict protected
- constructor Create();
- function Asn1GetHashCode(): Int32; override;
- public
- function GetString(): String; virtual; abstract;
- function ToString(): String; override;
- end;
- type
- /// <summary>
- /// Der Bit string object.
- /// </summary>
- TDerBitString = class(TDerStringBase, IDerBitString)
- strict private
- const
- FTable: array [0 .. 15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
- strict protected
- var
- FmData: TCryptoLibByteArray;
- FmPadBits: Int32;
- function GetmPadBits: Int32; inline;
- function GetmData: TCryptoLibByteArray; inline;
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- property mPadBits: Int32 read GetmPadBits;
- property mData: TCryptoLibByteArray read GetmData;
- public
- constructor Create(const data: TCryptoLibByteArray;
- padBits: Int32); overload;
- constructor Create(const data: TCryptoLibByteArray); overload;
- constructor Create(namedBits: Int32); overload;
- constructor Create(const obj: IAsn1Encodable); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; virtual;
- function GetBytes(): TCryptoLibByteArray; virtual;
- procedure Encode(const derOut: TStream); override;
- function GetInt32Value: Int32; virtual;
- property Int32Value: Int32 read GetInt32Value;
- /// <summary>
- /// return a Der Bit string from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a Bit string or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a Der Bit string instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerBitString; overload;
- static; inline;
- class function GetInstance(const obj: TCryptoLibByteArray): IDerBitString;
- overload; static;
- /// <summary>
- /// return a Der Bit string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBitString; overload; static; inline;
- class function FromAsn1Octets(const octets: TCryptoLibByteArray)
- : IDerBitString; static;
- end;
- type
- TBerBitString = class(TDerBitString, IBerBitString)
- public
- constructor Create(const data: TCryptoLibByteArray;
- padBits: Int32); overload;
- constructor Create(const data: TCryptoLibByteArray); overload;
- constructor Create(namedBits: Int32); overload;
- constructor Create(const obj: IAsn1Encodable); overload;
- procedure Encode(const derOut: TStream); override;
- end;
- type
- TBerGenerator = class abstract(TAsn1Generator, IBerGenerator)
- strict private
- var
- F_tagged, F_isExplicit: Boolean;
- F_tagNo: Int32;
- strict protected
- constructor Create(outStream: TStream); overload;
- constructor Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean); overload;
- procedure WriteHdr(tag: Int32);
- procedure WriteBerHeader(tag: Int32);
- procedure WriteBerBody(contentStream: TStream);
- procedure WriteBerEnd();
- public
- procedure AddObject(const obj: IAsn1Encodable); override;
- function GetRawOutputStream(): TStream; override;
- procedure Close(); override;
- end;
- type
- /// <summary>
- /// A BER Null object.
- /// </summary>
- TBerNull = class sealed(TDerNull, IBerNull)
- strict private
- class function GetInstance: IBerNull; static; inline;
- constructor Create(dummy: Int32);
- public
- procedure Encode(const derOut: TStream); override;
- class property Instance: IBerNull read GetInstance;
- end;
- type
- TBerSequenceGenerator = class(TBerGenerator, IBerSequenceGenerator)
- public
- constructor Create(outStream: TStream); overload;
- constructor Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean); overload;
- end;
- type
- TBerSequenceParser = class(TInterfacedObject, IAsn1SequenceParser,
- IAsn1Convertible, IBerSequenceParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; inline;
- end;
- type
- /// <summary>
- /// A Ber encoded set object
- /// </summary>
- TBerSet = class sealed(TDerSet, IBerSet)
- strict private
- class function GetEmpty: IBerSet; static; inline;
- public
- class function FromVector(const elementVector: IAsn1EncodableVector)
- : IBerSet; overload; static;
- class function FromVector(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean): IBerSet; overload; static;
- /// <summary>
- /// create an empty set
- /// </summary>
- constructor Create(); overload;
- /// <param name="element">
- /// a single object that makes up the set.
- /// </param>
- constructor Create(const element: IAsn1Encodable); overload;
- /// <param name="elementVector">
- /// a vector of objects making up the set.
- /// </param>
- constructor Create(const elementVector: IAsn1EncodableVector); overload;
- constructor Create(const v: IAsn1EncodableVector;
- needsSorting: Boolean); overload;
- destructor Destroy(); override;
- /// <summary>
- /// A note on the implementation: <br />As Ber requires the constructed,
- /// definite-length model to <br />be used for structured types, this
- /// varies slightly from the <br />ASN.1 descriptions given. Rather than
- /// just outputing Set, <br />we also have to specify Constructed, and
- /// the objects length. <br />
- /// </summary>
- procedure Encode(const derOut: TStream); override;
- class property Empty: IBerSet read GetEmpty;
- end;
- type
- TBerSetParser = class(TInterfacedObject, IAsn1SetParser, IAsn1Convertible,
- IBerSetParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; inline;
- end;
- type
- /// <summary>
- /// DER TaggedObject - in ASN.1 notation this is any object preceded by <br />
- /// a [n] where n is some number - these are assumed to follow the
- /// construction <br />rules (as with sequences). <br />
- /// </summary>
- TDerTaggedObject = class(TAsn1TaggedObject, IDerTaggedObject)
- public
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- /// <param name="obj">
- /// the tagged object.
- /// </param>
- constructor Create(tagNo: Int32; const obj: IAsn1Encodable); overload;
- /// <param name="explicitly">
- /// true if an explicitly tagged object.
- /// </param>
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- /// <param name="obj">
- /// the tagged object.
- /// </param>
- constructor Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable); overload;
- /// <summary>
- /// create an implicitly tagged object that contains a zero length
- /// sequence.
- /// </summary>
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- constructor Create(tagNo: Int32); overload;
- procedure Encode(const derOut: TStream); override;
- end;
- type
- /// <summary>
- /// BER TaggedObject - in ASN.1 notation this is any object preceded by <br />
- /// a [n] where n is some number - these are assumed to follow the
- /// construction <br />rules (as with sequences). <br />
- /// </summary>
- TBerTaggedObject = class(TDerTaggedObject, IBerTaggedObject)
- public
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- /// <param name="obj">
- /// the tagged object.
- /// </param>
- constructor Create(tagNo: Int32; const obj: IAsn1Encodable); overload;
- /// <param name="explicitly">
- /// true if an explicitly tagged object.
- /// </param>
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- /// <param name="obj">
- /// the tagged object.
- /// </param>
- constructor Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable); overload;
- /// <summary>
- /// create an implicitly tagged object that contains a zero length
- /// sequence.
- /// </summary>
- /// <param name="tagNo">
- /// the tag number for this object.
- /// </param>
- constructor Create(tagNo: Int32); overload;
- procedure Encode(const derOut: TStream); override;
- end;
- type
- TBerTaggedObjectParser = class(TInterfacedObject, IAsn1TaggedObjectParser,
- IAsn1Convertible, IBerTaggedObjectParser)
- strict private
- var
- F_constructed: Boolean;
- F_tagNumber: Int32;
- F_parser: IAsn1StreamParser;
- function GetIsConstructed: Boolean; inline;
- function GetTagNo: Int32; inline;
- public
- constructor Create(Constructed: Boolean; tagNumber: Int32;
- const parser: IAsn1StreamParser);
- destructor Destroy; override;
- function GetObjectParser(tag: Int32; isExplicit: Boolean)
- : IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object;
- property IsConstructed: Boolean read GetIsConstructed;
- property tagNo: Int32 read GetTagNo;
- end;
- type
- TDerBmpString = class(TDerStringBase, IDerBmpString)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- property Str: String read GetStr;
- /// <summary>
- /// basic constructor - byte encoded string.
- /// </summary>
- constructor Create(const astr: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor
- /// </summary>
- constructor Create(const astr: String); overload;
- function GetString(): String; override;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a BMP string from the given object.
- /// </summary>
- /// <param name="obj">
- /// the object we want converted.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerBmpString; overload;
- static; inline;
- /// <summary>
- /// return a BMP string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBmpString; overload; static; inline;
- end;
- type
- TDerBoolean = class(TAsn1Object, IDerBoolean)
- strict private
- var
- Fvalue: Byte;
- function GetIsTrue: Boolean; inline;
- constructor Create(Value: Boolean); overload;
- class function GetFalse: IDerBoolean; static; inline;
- class function GetTrue: IDerBoolean; static; inline;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function Asn1GetHashCode(): Int32; override;
- public
- constructor Create(const val: TCryptoLibByteArray); overload;
- procedure Encode(const derOut: TStream); override;
- function ToString(): String; override;
- property IsTrue: Boolean read GetIsTrue;
- class property True: IDerBoolean read GetTrue;
- class property False: IDerBoolean read GetFalse;
- /// <summary>
- /// return a DerBoolean from the passed in object.
- /// </summary>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerBoolean; overload;
- static; inline;
- /// <summary>
- /// return a DerBoolean from the passed in boolean.
- /// </summary>
- class function GetInstance(Value: Boolean): IDerBoolean; overload;
- static; inline;
- /// <summary>
- /// return a Boolean from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// explicitly true if the object is meant to be explicitly tagged false
- /// otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBoolean; overload; static; inline;
- class function FromOctetString(const Value: TCryptoLibByteArray)
- : IDerBoolean; static;
- end;
- type
- TDerEnumerated = class(TAsn1Object, IDerEnumerated)
- strict private
- class var
- Fcache: array [0 .. 11] of IDerEnumerated;
- var
- Fbytes: TCryptoLibByteArray;
- FStart: Int32;
- function GetValue: TBigInteger; inline;
- function GetBytes: TCryptoLibByteArray; inline;
- function GetIntValueExact: Int32; inline;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- function Asn1GetHashCode(): Int32; override;
- public
- constructor Create(val: Int32); overload;
- constructor Create(val: Int64); overload;
- constructor Create(const val: TBigInteger); overload;
- constructor Create(const bytes: TCryptoLibByteArray); overload;
- procedure Encode(const derOut: TStream); override;
- property Value: TBigInteger read GetValue;
- property bytes: TCryptoLibByteArray read GetBytes;
- property IntValueExact: Int32 read GetIntValueExact;
- function HasValue(const x: TBigInteger): Boolean;
- /// <summary>
- /// return an integer from the passed in object
- /// </summary>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerEnumerated; overload;
- static; inline;
- /// <summary>
- /// return an Enumerated from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerEnumerated; overload; static; inline;
- class function FromOctetString(const enc: TCryptoLibByteArray)
- : IDerEnumerated; static;
- end;
- type
- TDerGraphicString = class(TDerStringBase, IDerGraphicString)
- strict private
- var
- FmString: TCryptoLibByteArray;
- function GetmString: TCryptoLibByteArray; inline;
- protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- property mString: TCryptoLibByteArray read GetmString;
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- /// <param name="encoding">
- /// the byte encoding of the characters making up the string.
- /// </param>
- constructor Create(const encoding: TCryptoLibByteArray);
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a Graphic String from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a DerGraphicString or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerGraphicString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerGraphicString; overload;
- static; inline;
- class function GetInstance(const obj: TCryptoLibByteArray)
- : IDerGraphicString; overload; static;
- /// <summary>
- /// return a Graphic string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerGraphicString; overload; static; inline;
- end;
- type
- /// <summary>
- /// Class representing the DER-type External
- /// </summary>
- TDerExternal = class(TAsn1Object, IDerExternal)
- strict private
- var
- FdirectReference: IDerObjectIdentifier;
- FindirectReference: IDerInteger;
- FdataValueDescriptor, FexternalContent: IAsn1Object;
- Fencoding: Int32;
- function GetDataValueDescriptor: IAsn1Object;
- function GetDirectReference: IDerObjectIdentifier;
- /// <summary>
- /// <para>
- /// The encoding of the content. Valid values are
- /// </para>
- /// <para>
- /// <ul> <br /><li><code>0</code>
- /// single-ASN1-type</li> <br />
- /// <li><code>1</code> OCTET STRING</li> <br />
- /// <li><code>2</code> BIT STRING</li> <br />
- /// </ul>
- /// </para>
- /// </summary>
- function GetEncoding: Int32;
- function GetExternalContent: IAsn1Object;
- function GetIndirectReference: IDerInteger;
- procedure SetDataValueDescriptor(const Value: IAsn1Object);
- procedure SetDirectReference(const Value: IDerObjectIdentifier);
- procedure SetEncoding(const Value: Int32);
- procedure SetExternalContent(const Value: IAsn1Object);
- procedure SetIndirectReference(const Value: IDerInteger);
- class function GetObjFromVector(const v: IAsn1EncodableVector; Index: Int32)
- : IAsn1Object; static; inline;
- class procedure WriteEncodable(ms: TMemoryStream; const e: IAsn1Encodable);
- static; inline;
- strict protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- constructor Create(const vector: IAsn1EncodableVector); overload;
- /// <summary>
- /// Creates a new instance of DerExternal <br />See X.690 for more
- /// informations about the meaning of these parameters
- /// </summary>
- /// <param name="directReference">
- /// The direct reference or <code>null</code> if not set.
- /// </param>
- /// <param name="indirectReference">
- /// The indirect reference or <code>null</code> if not set.
- /// </param>
- /// <param name="dataValueDescriptor">
- /// The data value descriptor or <code>null</code> if not
- /// set.
- /// </param>
- /// <param name="externalData">
- /// The external data in its encoded form.
- /// </param>
- constructor Create(const directReference: IDerObjectIdentifier;
- const indirectReference: IDerInteger;
- const dataValueDescriptor: IAsn1Object;
- const externalData: IDerTaggedObject); overload;
- constructor Create(const directReference: IDerObjectIdentifier;
- const indirectReference: IDerInteger;
- const dataValueDescriptor: IAsn1Object; encoding: Int32;
- const externalData: IAsn1Object); overload;
- procedure Encode(const derOut: TStream); override;
- property dataValueDescriptor: IAsn1Object read GetDataValueDescriptor
- write SetDataValueDescriptor;
- property directReference: IDerObjectIdentifier read GetDirectReference
- write SetDirectReference;
- property encoding: Int32 read GetEncoding write SetEncoding;
- property ExternalContent: IAsn1Object read GetExternalContent
- write SetExternalContent;
- property indirectReference: IDerInteger read GetIndirectReference
- write SetIndirectReference;
- end;
- type
- TDerInteger = class sealed(TAsn1Object, IDerInteger)
- strict private
- class var
- FAllowUnsafeInteger: Boolean;
- class constructor CreateDerInteger();
- var
- Fbytes: TCryptoLibByteArray;
- FStart: Int32;
- function GetBytes: TCryptoLibByteArray; inline;
- function GetPositiveValue: TBigInteger; inline;
- function GetValue: TBigInteger; inline;
- function GetIntPositiveValueExact: Int32; inline;
- function GetIntValueExact: Int32; inline;
- class function GetAllowUnsafeInteger: Boolean; static; inline;
- class procedure SetAllowUnsafeInteger(const Value: Boolean); static; inline;
- strict protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- const
- SignExtSigned = Int32(-1);
- SignExtUnsigned = Int32($FF);
- constructor Create(Value: Int32); overload;
- constructor Create(Value: Int64); overload;
- constructor Create(const Value: TBigInteger); overload;
- constructor Create(const bytes: TCryptoLibByteArray); overload;
- constructor Create(const bytes: TCryptoLibByteArray;
- clone: Boolean); overload;
- property Value: TBigInteger read GetValue;
- property PositiveValue: TBigInteger read GetPositiveValue;
- property IntPositiveValueExact: Int32 read GetIntPositiveValueExact;
- property IntValueExact: Int32 read GetIntValueExact;
- property bytes: TCryptoLibByteArray read GetBytes;
- procedure Encode(const derOut: TStream); override;
- function HasValue(const x: TBigInteger): Boolean;
- function ToString(): String; override;
- // /**
- // * return an integer from the passed in object
- // *
- // * @exception ArgumentException if the object cannot be converted.
- // */
- class function GetInstance(const obj: TObject): IDerInteger;
- overload; static;
- // /**
- // * return an Integer from a tagged object.
- // *
- // * @param obj the tagged object holding the object we want
- // * @param isExplicit true if the object is meant to be explicitly
- // * tagged false otherwise.
- // * @exception ArgumentException if the tagged object cannot
- // * be converted.
- // */
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerInteger; overload; static; inline;
- /// <summary>
- /// Apply the correct validation for an INTEGER primitive following the
- /// BER rules.
- /// </summary>
- /// <param name="bytes">
- /// The raw encoding of the integer.
- /// </param>
- /// <returns>
- /// if the (in)put fails this validation.
- /// </returns>
- class function IsMalformed(const bytes: TCryptoLibByteArray)
- : Boolean; static;
- class function SignBytesToSkip(const bytes: TCryptoLibByteArray)
- : Int32; static;
- class function IntValue(const bytes: TCryptoLibByteArray;
- start, signExt: Int32): Int32; static;
- class property AllowUnsafeInteger: Boolean read GetAllowUnsafeInteger
- write SetAllowUnsafeInteger;
- end;
- type
- TDerExternalParser = class(TAsn1Encodable, IDerExternalParser)
- strict private
- var
- F_parser: IAsn1StreamParser;
- public
- constructor Create(const parser: IAsn1StreamParser);
- function ReadObject(): IAsn1Convertible; inline;
- function ToAsn1Object(): IAsn1Object; override;
- end;
- type
- TDerOctetStringParser = class(TInterfacedObject, IAsn1OctetStringParser,
- IAsn1Convertible, IDerOctetStringParser)
- strict private
- var
- FStream: TStream;
- public
- constructor Create(stream: TStream);
- destructor Destroy(); override;
- function GetOctetStream(): TStream; inline;
- function ToAsn1Object(): IAsn1Object;
- end;
- type
- TDerGeneralString = class(TDerStringBase, IDerGeneralString)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- constructor Create(const Str: TCryptoLibByteArray); overload;
- constructor Create(const Str: String); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- class function GetInstance(const obj: TObject): IDerGeneralString; overload;
- static; inline;
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerGeneralString; overload; static; inline;
- end;
- type
- TDerGenerator = class abstract(TAsn1Generator, IDerGenerator)
- strict private
- var
- F_tagged, F_isExplicit: Boolean;
- F_tagNo: Int32;
- class procedure WriteLength(const outStr: TStream; length: Int32); static;
- strict protected
- constructor Create(const outStream: TStream); overload;
- constructor Create(const outStream: TStream; tagNo: Int32;
- isExplicit: Boolean); overload;
- public
- procedure WriteDerEncoded(tag: Int32;
- const bytes: TCryptoLibByteArray); overload;
- class procedure WriteDerEncoded(const outStream: TStream; tag: Int32;
- const bytes: TCryptoLibByteArray); overload; static;
- class procedure WriteDerEncoded(const outStr: TStream; tag: Int32;
- const inStr: TStream); overload; static;
- end;
- type
- /// <summary>
- /// Der IA5String object - this is an ascii string.
- /// </summary>
- TDerIA5String = class(TDerStringBase, IDerIA5String)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- strict protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor - without validation.
- /// </summary>
- constructor Create(const Str: String); overload;
- /// <summary>
- /// Constructor with optional validation.
- /// </summary>
- /// <param name="Str">
- /// the base string to wrap.
- /// </param>
- /// <param name="validate">
- /// whether or not to check the string.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if validate is true and the string contains characters that should
- /// not be in an IA5String.
- /// </exception>
- constructor Create(const Str: String; validate: Boolean); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a DerIA5String from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a DerIA5String or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerIA5String instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerIA5String; overload;
- static; inline;
- /// <summary>
- /// return a DerIA5String from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerIA5String; overload; static; inline;
- /// <summary>
- /// return true if the passed in String can be represented without loss
- /// as an IA5String, false otherwise.
- /// </summary>
- /// <param name="Str">
- /// true if in printable set, false otherwise.
- /// </param>
- class function IsIA5String(const Str: String): Boolean; static; inline;
- end;
- type
- /// <summary>
- /// Der NumericString object - this is an ascii string of characters
- /// {0,1,2,3,4,5,6,7,8,9, }.
- /// </summary>
- TDerNumericString = class(TDerStringBase, IDerNumericString)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor - without validation.
- /// </summary>
- constructor Create(const Str: String); overload;
- /// <summary>
- /// Constructor with optional validation.
- /// </summary>
- /// <param name="Str">
- /// the base string to wrap.
- /// </param>
- /// <param name="validate">
- /// whether or not to check the string.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if validate is true and the string contains characters that should
- /// not be in an IA5String.
- /// </exception>
- constructor Create(const Str: String; validate: Boolean); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a Numeric string from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a DerNumericString or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerNumericString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerNumericString; overload;
- static; inline;
- /// <summary>
- /// return a Numeric String from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerNumericString; overload; static; inline;
- /// <summary>
- /// Return true if the string can be represented as a NumericString
- /// ('0'..'9', ' ')
- /// </summary>
- /// <param name="Str">
- /// string to validate.
- /// </param>
- /// <returns>
- /// true if numeric, false otherwise.
- /// </returns>
- class function IsNumericString(const Str: String): Boolean; static; inline;
- end;
- type
- /// <summary>
- /// Der PrintableString object.
- /// </summary>
- TDerPrintableString = class(TDerStringBase, IDerPrintableString)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor - without validation.
- /// </summary>
- constructor Create(const Str: String); overload;
- /// <summary>
- /// Constructor with optional validation.
- /// </summary>
- /// <param name="Str">
- /// the base string to wrap.
- /// </param>
- /// <param name="validate">
- /// whether or not to check the string.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if validate is true and the string contains characters that should
- /// not be in an PrintableString.
- /// </exception>
- constructor Create(const Str: String; validate: Boolean); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- property Str: String read GetStr;
- /// <summary>
- /// return a printable string from the passed in object.
- /// </summary>
- /// <param name="obj">
- /// a DerPrintableString or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerPrintableString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerPrintableString;
- overload; static; inline;
- /// <summary>
- /// return a Printable string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerPrintableString; overload; static; inline;
- /// <summary>
- /// return true if the passed in String can be represented without loss
- /// as a PrintableString, false otherwise.
- /// </summary>
- /// <param name="Str">
- /// string to validate.
- /// </param>
- /// <returns>
- /// return true if in printable set, false otherwise.
- /// </returns>
- class function IsPrintableString(const Str: String): Boolean;
- static; inline;
- end;
- type
- TDerSequenceGenerator = class(TDerGenerator, IDerSequenceGenerator)
- strict private
- var
- F_bOut: TMemoryStream;
- public
- constructor Create(outStream: TStream); overload;
- constructor Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean); overload;
- destructor Destroy(); override;
- procedure AddObject(const obj: IAsn1Encodable); override;
- function GetRawOutputStream(): TStream; override;
- procedure Close(); override;
- end;
- type
- /// <summary>
- /// Der T61String (also the teletex string) - 8-bit characters
- /// </summary>
- TDerT61String = class(TDerStringBase, IDerT61String)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- class function GetEncoding: TEncoding; static; inline;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor
- /// </summary>
- constructor Create(const Str: String); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a T61 string from the passed in object.
- /// </summary>
- /// <param name="obj">
- /// a Der T61 string or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a Der T61 string instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerT61String; overload;
- static; inline;
- /// <summary>
- /// return a Der T61 string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerT61String; overload; static; inline;
- end;
- type
- /// <summary>
- /// Der UniversalString object.
- /// </summary>
- TDerUniversalString = class(TDerStringBase, IDerUniversalString)
- strict private
- var
- FStr: TCryptoLibByteArray;
- const
- FTable: array [0 .. 15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
- function GetStr: TCryptoLibByteArray; inline;
- property Str: TCryptoLibByteArray read GetStr;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - byte encoded string.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a Universal String from the passed in object.
- /// </summary>
- /// <param name="obj">
- /// a Der T61 string or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a Der UniversalString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerUniversalString;
- overload; static; inline;
- /// <summary>
- /// return a Der UniversalString from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerUniversalString; overload; static; inline;
- end;
- type
- /// <summary>
- /// Der UTF8String object.
- /// </summary>
- TDerUtf8String = class(TDerStringBase, IDerUtf8String)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- strict protected
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor
- /// </summary>
- constructor Create(const Str: String); overload;
- function GetString(): String; override;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return an UTF8 string from the passed in object.
- /// </summary>
- /// <param name="obj">
- /// a Der UTF8String or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a Der UTF8String instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerUtf8String; overload;
- static; inline;
- /// <summary>
- /// return a Der UTF8String from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerUtf8String; overload; static; inline;
- end;
- type
- TDerVideotexString = class(TDerStringBase, IDerVideotexString)
- strict private
- var
- FmString: TCryptoLibByteArray;
- function GetmString: TCryptoLibByteArray; inline;
- protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- property mString: TCryptoLibByteArray read GetmString;
- /// <summary>
- /// basic constructor - with bytes.
- /// </summary>
- /// <param name="encoding">
- /// the byte encoding of the characters making up the string.
- /// </param>
- constructor Create(const encoding: TCryptoLibByteArray);
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a Videotex String from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a DerVideotexString or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerVideotexString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerVideotexString;
- overload; static; inline;
- class function GetInstance(const obj: TCryptoLibByteArray)
- : IDerVideotexString; overload; static;
- /// <summary>
- /// return a Videotex string from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerVideotexString; overload; static; inline;
- end;
- type
- /// <summary>
- /// Der VisibleString object.
- /// </summary>
- TDerVisibleString = class(TDerStringBase, IDerVisibleString)
- strict private
- var
- FStr: String;
- function GetStr: String; inline;
- property Str: String read GetStr;
- strict protected
- function Asn1GetHashCode(): Int32; override;
- function Asn1Equals(const asn1Object: IAsn1Object): Boolean; override;
- public
- /// <summary>
- /// basic constructor - byte encoded string.
- /// </summary>
- constructor Create(const Str: TCryptoLibByteArray); overload;
- /// <summary>
- /// basic constructor
- /// </summary>
- constructor Create(const Str: String); overload;
- function GetString(): String; override;
- function GetOctets(): TCryptoLibByteArray; inline;
- procedure Encode(const derOut: TStream); override;
- /// <summary>
- /// return a DerVisibleString from the passed in object
- /// </summary>
- /// <param name="obj">
- /// a DerVisibleString or an object that can be converted into one.
- /// </param>
- /// <returns>
- /// return a DerVisibleString instance, or null.
- /// </returns>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: TObject): IDerVisibleString; overload;
- static; inline;
- /// <summary>
- /// return a DerVisibleString from a tagged object.
- /// </summary>
- /// <param name="obj">
- /// the tagged object holding the object we want
- /// </param>
- /// <param name="isExplicit">
- /// true if the object is meant to be explicitly tagged false otherwise.
- /// </param>
- /// <exception cref="ClpCryptoLibTypes|EArgumentCryptoLibException">
- /// if the tagged object cannot be converted.
- /// </exception>
- class function GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerVisibleString; overload; static; inline;
- end;
- implementation
- { TStreamHelper }
- function TStreamHelper.ReadByte: Int32;
- var
- buffer: TCryptoLibByteArray;
- begin
- System.SetLength(buffer, 1);
- if (TStreamSorter.Read(Self, buffer, 0, 1) = 0) then
- begin
- result := -1;
- end
- else
- begin
- result := Int32(buffer[0]);
- end;
- end;
- procedure TStreamHelper.WriteByte(b: Byte);
- var
- oneByteArray: TCryptoLibByteArray;
- begin
- System.SetLength(oneByteArray, 1);
- oneByteArray[0] := b;
- // Self.Write(oneByteArray, 0, 1);
- Self.Write(oneByteArray[0], 1);
- end;
- { TStreamSorter }
- class function TStreamSorter.Read(input: TStream;
- var buffer: TCryptoLibByteArray; offset, count: Int32): Int32;
- begin
- if input is TIndefiniteLengthInputStream then
- begin
- result := (input as TIndefiniteLengthInputStream).
- Read(buffer, offset, count);
- end
- else if input is TDefiniteLengthInputStream then
- begin
- result := (input as TDefiniteLengthInputStream).Read(buffer, offset, count);
- end
- else if input is TConstructedOctetStream then
- begin
- result := (input as TConstructedOctetStream).Read(buffer, offset, count);
- end
- else
- begin
- result := input.Read(buffer[offset], count);
- end;
- end;
- class function TStreamSorter.ReadByte(input: TStream): Int32;
- begin
- if input is TIndefiniteLengthInputStream then
- begin
- result := (input as TIndefiniteLengthInputStream).ReadByte();
- end
- else if input is TDefiniteLengthInputStream then
- begin
- result := (input as TDefiniteLengthInputStream).ReadByte();
- end
- else if input is TConstructedOctetStream then
- begin
- result := (input as TConstructedOctetStream).ReadByte();
- end
- else
- begin
- result := input.ReadByte();
- end;
- end;
- { TStreamUtils }
- class procedure TStreamUtils.Drain(const inStr: TStream);
- var
- bs: TCryptoLibByteArray;
- begin
- System.SetLength(bs, BufferSize);
- while (TStreamSorter.Read(inStr, bs, 0, System.length(bs)) > 0) do
- begin
- // do nothing
- end;
- end;
- class procedure TStreamUtils.PipeAll(const inStr, outStr: TStream);
- var
- numRead: Int32;
- bs: TCryptoLibByteArray;
- begin
- System.SetLength(bs, BufferSize);
- numRead := TStreamSorter.Read(inStr, bs, 0, System.length(bs));
- while ((numRead) > 0) do
- begin
- outStr.Write(bs[0], numRead);
- numRead := TStreamSorter.Read(inStr, bs, 0, System.length(bs));
- end;
- end;
- class function TStreamUtils.PipeAllLimited(const inStr: TStream; limit: Int64;
- const outStr: TStream): Int64;
- var
- bs: TCryptoLibByteArray;
- numRead: Int32;
- total: Int64;
- begin
- System.SetLength(bs, BufferSize);
- total := 0;
- numRead := TStreamSorter.Read(inStr, bs, 0, System.length(bs));
- while ((numRead) > 0) do
- begin
- if ((limit - total) < numRead) then
- begin
- raise EStreamOverflowCryptoLibException.CreateRes(@SDataOverflow);
- end;
- total := total + numRead;
- outStr.Write(bs[0], numRead);
- numRead := TStreamSorter.Read(inStr, bs, 0, System.length(bs));
- end;
- result := total;
- end;
- class function TStreamUtils.ReadAll(const inStr: TStream): TCryptoLibByteArray;
- var
- buf: TMemoryStream;
- begin
- buf := TMemoryStream.Create();
- try
- PipeAll(inStr, buf);
- System.SetLength(result, buf.Size);
- buf.Position := 0;
- buf.Read(result[0], buf.Size);
- finally
- buf.Free;
- end;
- end;
- class function TStreamUtils.ReadAllLimited(const inStr: TStream; limit: Int32)
- : TCryptoLibByteArray;
- var
- buf: TMemoryStream;
- begin
- buf := TMemoryStream.Create();
- try
- PipeAllLimited(inStr, limit, buf);
- System.SetLength(result, buf.Size);
- buf.Position := 0;
- buf.Read(result[0], buf.Size);
- finally
- buf.Free;
- end;
- end;
- class function TStreamUtils.ReadFully(const inStr: TStream;
- var buf: TCryptoLibByteArray; off, len: Int32): Int32;
- var
- totalRead, numRead: Int32;
- begin
- totalRead := 0;
- while (totalRead < len) do
- begin
- numRead := TStreamSorter.Read(inStr, buf, off + totalRead, len - totalRead);
- if (numRead < 1) then
- begin
- break;
- end;
- totalRead := totalRead + numRead;
- end;
- result := totalRead;
- end;
- class function TStreamUtils.WriteBufTo(const buf: TMemoryStream;
- const output: TCryptoLibByteArray; offset: Int32): Int32;
- var
- bytes: TCryptoLibByteArray;
- begin
- buf.Position := 0;
- System.SetLength(bytes, buf.Size);
- buf.Read(bytes[0], buf.Size);
- System.Move(bytes[0], output[offset], System.length(bytes) *
- System.SizeOf(Byte));
- result := System.length(bytes);
- end;
- class procedure TStreamUtils.WriteZeroes(const outStr: TStream; count: Int64);
- var
- zeroes: TCryptoLibByteArray;
- begin
- System.SetLength(zeroes, BufferSize);
- while (count > BufferSize) do
- begin
- outStr.Write(zeroes[0], BufferSize);
- count := count - BufferSize;
- end;
- outStr.Write(zeroes[0], Int32(count));
- end;
- class function TStreamUtils.ReadFully(const inStr: TStream;
- var buf: TCryptoLibByteArray): Int32;
- begin
- result := ReadFully(inStr, buf, 0, System.length(buf));
- end;
- class procedure TStreamUtils.WriteBufTo(const buf: TMemoryStream;
- const output: TStream);
- begin
- output.CopyFrom(buf, buf.Size);
- end;
- { TBaseInputStream }
- function TBaseInputStream.GetPosition: Int64;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- function TBaseInputStream.GetSize: Int64;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- {$IFNDEF _FIXINSIGHT_}
- function TBaseInputStream.Read(var buffer; count: LongInt): LongInt;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- function TBaseInputStream.Write(const buffer; count: LongInt): LongInt;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- {$ENDIF}
- function TBaseInputStream.ReadByte: Int32;
- var
- buffer: TCryptoLibByteArray;
- begin
- System.SetLength(buffer, 1);
- // if (Read(Buffer, 0, 1) = 0) then
- if (TStreamSorter.Read(Self, buffer, 0, 1) = 0) then
- begin
- result := -1;
- end
- else
- begin
- result := Int32(buffer[0]);
- end;
- end;
- function TBaseInputStream.Seek(offset: LongInt; Origin: Word): LongInt;
- begin
- result := Seek(Int64(offset), TSeekOrigin(Origin));
- end;
- {$IFNDEF _FIXINSIGHT_}
- function TBaseInputStream.Seek(const offset: Int64; Origin: TSeekOrigin): Int64;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- procedure TBaseInputStream.SetPosition(const Pos: Int64);
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- {$ENDIF}
- procedure TBaseInputStream.SetSize(const NewSize: Int64);
- begin
- SetSize(LongInt(NewSize));
- end;
- procedure TBaseInputStream.SetSize(NewSize: LongInt);
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- procedure TBaseInputStream.SetSize64(const NewSize: Int64);
- begin
- SetSize(NewSize);
- end;
- function TBaseInputStream.Read(buffer: TCryptoLibByteArray;
- offset, count: LongInt): LongInt;
- var
- &pos, endPoint, b: Int32;
- begin
- Pos := offset;
- try
- endPoint := offset + count;
- while (Pos < endPoint) do
- begin
- b := ReadByte();
- if (b = -1) then
- begin
- break;
- end;
- buffer[Pos] := Byte(b);
- System.Inc(Pos);
- end;
- except
- on e: EIOCryptoLibException do
- begin
- if (Pos = offset) then
- raise;
- end;
- end;
- result := Pos - offset;
- end;
- {$IFNDEF _FIXINSIGHT_}
- function TBaseInputStream.Write(const buffer: TCryptoLibByteArray;
- offset, count: LongInt): LongInt;
- begin
- raise ENotSupportedCryptoLibException.Create('');
- end;
- {$ENDIF}
- { TFilterStream }
- constructor TFilterStream.Create(const s: TStream);
- begin
- inherited Create();
- Fs := s;
- end;
- function TFilterStream.GetPosition: Int64;
- begin
- result := Fs.Position;
- end;
- procedure TFilterStream.SetPosition(const Value: Int64);
- begin
- Fs.Position := Value;
- end;
- function TFilterStream.Write(const buffer; count: LongInt): LongInt;
- begin
- result := Fs.Write(PByte(buffer), count);
- end;
- procedure TFilterStream.WriteByte(Value: Byte);
- begin
- Fs.WriteByte(Value);
- end;
- function TFilterStream.GetSize: Int64;
- begin
- result := Fs.Size;
- end;
- function TFilterStream.Read(var buffer; count: LongInt): LongInt;
- begin
- result := Fs.Read(PByte(buffer), count);
- end;
- function TFilterStream.ReadByte: Int32;
- begin
- result := TStreamSorter.ReadByte(Fs);
- end;
- function TFilterStream.Seek(const offset: Int64; Origin: TSeekOrigin): Int64;
- begin
- result := Fs.Seek(offset, Origin);
- end;
- { TLimitedInputStream }
- constructor TLimitedInputStream.Create(inStream: TStream; limit: Int32);
- begin
- Inherited Create();
- F_in := inStream;
- F_limit := limit;
- end;
- function TLimitedInputStream.GetRemaining: Int32;
- begin
- // TODO: maybe one day this can become more accurate
- result := F_limit;
- end;
- procedure TLimitedInputStream.SetParentEofDetect(&on: Boolean);
- var
- indefiniteLengthInputStream: TIndefiniteLengthInputStream;
- begin
- if F_in is TIndefiniteLengthInputStream then
- begin
- indefiniteLengthInputStream := F_in as TIndefiniteLengthInputStream;
- indefiniteLengthInputStream.SetEofOn00(&on);
- end;
- end;
- { TDefiniteLengthInputStream }
- constructor TDefiniteLengthInputStream.Create(inStream: TStream; length: Int32);
- begin
- Inherited Create(inStream, length);
- if (length < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInvalidLength);
- end;
- F_originalLength := length;
- F_remaining := length;
- if (length = 0) then
- begin
- SetParentEofDetect(True);
- end;
- end;
- class function TDefiniteLengthInputStream.GetEmptyBytes: TCryptoLibByteArray;
- begin
- result := Nil;
- end;
- function TDefiniteLengthInputStream.GetRemaining: Int32;
- begin
- result := F_remaining;
- end;
- function TDefiniteLengthInputStream.Read(buf: TCryptoLibByteArray;
- off, len: LongInt): LongInt;
- var
- toRead, numRead: Int32;
- begin
- if (F_remaining = 0) then
- begin
- result := 0;
- Exit;
- end;
- toRead := Min(len, F_remaining);
- numRead := TStreamSorter.Read(F_in, buf, off, toRead);
- if (numRead < 1) then
- begin
- raise EEndOfStreamCryptoLibException.CreateResFmt(@SEndOfStreamTwo,
- [F_originalLength, F_remaining]);
- end;
- F_remaining := F_remaining - numRead;
- if (F_remaining = 0) then
- begin
- SetParentEofDetect(True);
- end;
- result := numRead;
- end;
- procedure TDefiniteLengthInputStream.ReadAllIntoByteArray
- (var buf: TCryptoLibByteArray);
- begin
- if (F_remaining <> System.length(buf)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInvalidBufferLength);
- end;
- F_remaining := F_remaining - TStreamUtils.ReadFully(F_in, buf);
- if ((F_remaining <> 0)) then
- begin
- raise EEndOfStreamCryptoLibException.CreateResFmt(@SEndOfStreamTwo,
- [F_originalLength, F_remaining]);
- end;
- SetParentEofDetect(True);
- end;
- function TDefiniteLengthInputStream.ReadByte: Int32;
- begin
- if (F_remaining = 0) then
- begin
- result := -1;
- Exit;
- end;
- // result := F_in.ReadByte();
- result := TStreamSorter.ReadByte(F_in);
- if (result < 0) then
- begin
- raise EEndOfStreamCryptoLibException.CreateResFmt(@SEndOfStreamTwo,
- [F_originalLength, F_remaining]);
- end;
- System.Dec(F_remaining);
- if (F_remaining = 0) then
- begin
- SetParentEofDetect(True);
- end;
- end;
- function TDefiniteLengthInputStream.ToArray: TCryptoLibByteArray;
- var
- bytes: TCryptoLibByteArray;
- begin
- if (F_remaining = 0) then
- begin
- result := EmptyBytes;
- Exit;
- end;
- System.SetLength(bytes, F_remaining);
- F_remaining := F_remaining - TStreamUtils.ReadFully(F_in, bytes);
- if (F_remaining <> 0) then
- begin
- raise EEndOfStreamCryptoLibException.CreateResFmt(@SEndOfStreamTwo,
- [F_originalLength, F_remaining]);
- end;
- SetParentEofDetect(True);
- result := bytes;
- end;
- { TAsn1InputStream }
- class function TAsn1InputStream.FindLimit(const input: TStream): Int32;
- var
- limitedInputStream: TLimitedInputStream;
- mem: TMemoryStream;
- begin
- limitedInputStream := input as TLimitedInputStream;
- if (limitedInputStream <> Nil) then
- begin
- result := limitedInputStream.GetRemaining();
- Exit;
- end
- else if (input is TMemoryStream) then
- begin
- mem := input as TMemoryStream;
- result := Int32(mem.Size - mem.Position);
- Exit;
- end;
- result := System.High(Int32);
- end;
- class function TAsn1InputStream.GetBuffer(const defIn
- : TDefiniteLengthInputStream; const tmpBuffers: TCryptoLibMatrixByteArray)
- : TCryptoLibByteArray;
- var
- len: Int32;
- buf, temp: TCryptoLibByteArray;
- begin
- len := defIn.GetRemaining();
- if (len >= System.length(tmpBuffers)) then
- begin
- result := defIn.ToArray();
- Exit;
- end;
- buf := tmpBuffers[len];
- if (buf = Nil) then
- begin
- System.SetLength(temp, len);
- tmpBuffers[len] := temp;
- buf := tmpBuffers[len];
- end;
- defIn.ReadAllIntoByteArray(buf);
- result := buf;
- end;
- class function TAsn1InputStream.CreatePrimitiveDerObject(tagNo: Int32;
- const defIn: TDefiniteLengthInputStream;
- const tmpBuffers: TCryptoLibMatrixByteArray): IAsn1Object;
- var
- bytes: TCryptoLibByteArray;
- begin
- case tagNo of
- TAsn1Tags.Boolean:
- begin
- result := TDerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
- Exit;
- end;
- TAsn1Tags.Enumerated:
- begin
- result := TDerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
- Exit;
- end;
- TAsn1Tags.ObjectIdentifier:
- begin
- result := TDerObjectIdentifier.FromOctetString
- (GetBuffer(defIn, tmpBuffers));
- Exit;
- end;
- end;
- bytes := defIn.ToArray();
- case tagNo of
- TAsn1Tags.BitString:
- begin
- result := TDerBitString.FromAsn1Octets(bytes);
- Exit;
- end;
- TAsn1Tags.BmpString:
- begin
- result := TDerBmpString.Create(bytes);
- Exit;
- end;
- // TAsn1Tags.GeneralizedTime:
- // begin
- // result := TDerGeneralizedTime.Create(bytes);
- // Exit;
- // end;
- TAsn1Tags.GeneralString:
- begin
- result := TDerGeneralString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.GraphicString:
- begin
- result := TDerGraphicString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.IA5String:
- begin
- result := TDerIA5String.Create(bytes);
- Exit;
- end;
- TAsn1Tags.Integer:
- begin
- result := TDerInteger.Create(bytes);
- Exit;
- end;
- TAsn1Tags.Null:
- begin
- // actual content is ignored (enforce 0 length?)
- result := TDerNull.Instance;
- Exit;
- end;
- TAsn1Tags.NumericString:
- begin
- result := TDerNumericString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.OctetString:
- begin
- result := TDerOctetString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.PrintableString:
- begin
- result := TDerPrintableString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.T61String:
- begin
- result := TDerT61String.Create(bytes);
- Exit;
- end;
- TAsn1Tags.UniversalString:
- begin
- result := TDerUniversalString.Create(bytes);
- Exit;
- end;
- // TAsn1Tags.UtcTime:
- // begin
- // result := TDerUtcTime.Create(bytes);
- // Exit;
- // end;
- TAsn1Tags.Utf8String:
- begin
- result := TDerUtf8String.Create(bytes);
- Exit;
- end;
- TAsn1Tags.VideotexString:
- begin
- result := TDerVideotexString.Create(bytes);
- Exit;
- end;
- TAsn1Tags.VisibleString:
- begin
- result := TDerVisibleString.Create(bytes);
- Exit;
- end;
- else
- begin
- raise EIOCryptoLibException.CreateResFmt(@SUnknownTag, [tagNo]);
- end;
- end;
- end;
- destructor TAsn1InputStream.Destroy;
- begin
- FStream.Free;
- inherited Destroy;
- end;
- constructor TAsn1InputStream.Create(const inputStream: TStream; limit: Int32);
- begin
- Inherited Create(inputStream);
- Flimit := limit;
- System.SetLength(FtmpBuffers, 16);
- end;
- constructor TAsn1InputStream.Create(const inputStream: TStream);
- begin
- Create(inputStream, FindLimit(inputStream));
- end;
- constructor TAsn1InputStream.Create(const input: TCryptoLibByteArray);
- begin
- // used TBytesStream here for one pass creation and population with byte array :)
- FStream := TBytesStream.Create(input);
- Create(FStream, System.length(input));
- end;
- class function TAsn1InputStream.ReadLength(const s: TStream;
- limit: Int32): Int32;
- var
- &length, Size, next, I: Int32;
- begin
- length := TStreamSorter.ReadByte(s);
- if (length < 0) then
- begin
- raise EEndOfStreamCryptoLibException.CreateRes(@SInvalidEnd);
- end;
- if (length = $80) then
- begin
- result := -1; // indefinite-length encoding
- Exit;
- end;
- if (length > 127) then
- begin
- Size := length and $7F;
- // Note: The invalid long form "$ff" (see X.690 8.1.3.5c) will be caught here
- if (Size > 4) then
- begin
- raise EIOCryptoLibException.CreateResFmt(@SInvalidDerLength, [Size]);
- end;
- length := 0;
- I := 0;
- while I < Size do
- begin
- next := TStreamSorter.ReadByte(s);
- if (next < 0) then
- begin
- raise EEndOfStreamCryptoLibException.CreateRes(@SEndOfStream);
- end;
- length := (length shl 8) + next;
- System.Inc(I);
- end;
- if (length < 0) then
- begin
- raise EIOCryptoLibException.CreateRes(@SNegativeLength);
- end;
- if (length >= limit) then // after all we must have read at least 1 byte
- begin
- raise EIOCryptoLibException.CreateRes(@SOutOfBoundsLength);
- end;
- end;
- result := length;
- end;
- function TAsn1InputStream.ReadObject: IAsn1Object;
- var
- tag, tagNo, &length: Int32;
- IsConstructed: Boolean;
- indIn: TIndefiniteLengthInputStream;
- sp: IAsn1StreamParser;
- begin
- tag := ReadByte();
- if (tag <= 0) then
- begin
- if (tag = 0) then
- begin
- raise EIOCryptoLibException.CreateRes(@SEndOfContent);
- end;
- result := Nil;
- Exit;
- end;
- //
- // calculate tag number
- //
- tagNo := ReadTagNumber(Fs, tag);
- IsConstructed := (tag and TAsn1Tags.Constructed) <> 0;
- //
- // calculate length
- //
- length := ReadLength(Fs, Flimit);
- if (length < 0) then // indefinite length method
- begin
- if (not IsConstructed) then
- begin
- raise EIOCryptoLibException.CreateRes(@SIndefiniteLength);
- end;
- indIn := TIndefiniteLengthInputStream.Create(Fs, Flimit);
- sp := TAsn1StreamParser.Create(indIn, Flimit);
- if ((tag and TAsn1Tags.Application) <> 0) then
- begin
- result := (TBerApplicationSpecificParser.Create(tagNo, sp)
- as IBerApplicationSpecificParser).ToAsn1Object();
- Exit;
- end;
- if ((tag and TAsn1Tags.Tagged) <> 0) then
- begin
- result := (TBerTaggedObjectParser.Create(True, tagNo, sp)
- as IBerTaggedObjectParser).ToAsn1Object();
- Exit;
- end;
- // TODO There are other tags that may be constructed (e.g. BitString)
- case tagNo of
- TAsn1Tags.OctetString:
- begin
- result := (TBerOctetStringParser.Create(sp) as IBerOctetStringParser)
- .ToAsn1Object();
- Exit;
- end;
- TAsn1Tags.Sequence:
- begin
- result := (TBerSequenceParser.Create(sp) as IBerSequenceParser)
- .ToAsn1Object();
- Exit;
- end;
- TAsn1Tags.&Set:
- begin
- result := (TBerSetParser.Create(sp) as IBerSetParser).ToAsn1Object();
- Exit;
- end;
- TAsn1Tags.External:
- begin
- result := (TDerExternalParser.Create(sp) as IDerExternalParser)
- .ToAsn1Object();
- Exit;
- end;
- else
- begin
- raise EIOCryptoLibException.CreateRes(@SUnknownBerObject);
- end;
- end;
- end
- else
- begin
- try
- result := BuildObject(tag, tagNo, length);
- except
- on e: EArgumentCryptoLibException do
- begin
- raise EAsn1CryptoLibException.CreateResFmt(@SCorruptedStream,
- [e.Message]);
- end;
- end;
- end;
- end;
- function TAsn1InputStream.ReadVector(const dIn: TDefiniteLengthInputStream)
- : IAsn1EncodableVector;
- var
- v: IAsn1EncodableVector;
- o: IAsn1Object;
- subStream: TAsn1InputStream;
- begin
- if (dIn.Remaining < 1) then
- begin
- result := TAsn1EncodableVector.Create(0) as IAsn1EncodableVector;
- Exit;
- end;
- subStream := TAsn1InputStream.Create(dIn);
- try
- v := TAsn1EncodableVector.Create();
- o := subStream.ReadObject();
- while (o <> Nil) do
- begin
- v.Add([o]);
- o := subStream.ReadObject();
- end;
- finally
- subStream.Free;
- end;
- result := v;
- end;
- function TAsn1InputStream.BuildObject(tag, tagNo, length: Int32): IAsn1Object;
- var
- IsConstructed: Boolean;
- defIn: TDefiniteLengthInputStream;
- v: IAsn1EncodableVector;
- strings: TList<IDerOctetString>;
- I: Int32;
- begin
- IsConstructed := (tag and TAsn1Tags.Constructed) <> 0;
- defIn := TDefiniteLengthInputStream.Create(Fs, length);
- if ((tag and TAsn1Tags.Application) <> 0) then
- begin
- try
- result := TDerApplicationSpecific.Create(IsConstructed, tagNo,
- defIn.ToArray());
- Exit;
- finally
- defIn.Free;
- end;
- end;
- if ((tag and TAsn1Tags.Tagged) <> 0) then
- begin
- result := (TAsn1StreamParser.Create(defIn) as IAsn1StreamParser)
- .ReadTaggedObject(IsConstructed, tagNo);
- Exit;
- end;
- if (IsConstructed) then
- begin
- // TODO There are other tags that may be constructed (e.g. BitString)
- case (tagNo) of
- TAsn1Tags.OctetString:
- //
- // yes, people actually do this...
- //
- begin
- try
- v := ReadVector(defIn);
- strings := TList<IDerOctetString>.Create;
- strings.capacity := v.count;
- I := 0;
- while (I <> v.count) do
- begin
- strings.Add(v[I] as IDerOctetString);
- end;
- result := TBerOctetString.Create(strings);
- Exit;
- finally
- defIn.Free;
- end;
- end;
- TAsn1Tags.Sequence:
- begin
- try
- result := CreateDerSequence(defIn);
- Exit;
- finally
- defIn.Free;
- end;
- end;
- TAsn1Tags.&Set:
- begin
- try
- result := CreateDerSet(defIn);
- Exit;
- finally
- defIn.Free;
- end;
- end;
- TAsn1Tags.External:
- begin
- try
- result := TDerExternal.Create(ReadVector(defIn));
- Exit;
- finally
- defIn.Free;
- end;
- end;
- else
- begin
- defIn.Free; // free the stream incase an unsupported tag is encountered.
- raise EIOCryptoLibException.CreateResFmt(@SUnknownTag, [tagNo]);
- end;
- end;
- end;
- try
- result := CreatePrimitiveDerObject(tagNo, defIn, FtmpBuffers);
- finally
- defIn.Free;
- end;
- end;
- function TAsn1InputStream.CreateDerSequence
- (const dIn: TDefiniteLengthInputStream): IDerSequence;
- begin
- result := TDerSequence.FromVector(ReadVector(dIn));
- end;
- function TAsn1InputStream.CreateDerSet(const dIn
- : TDefiniteLengthInputStream): IDerSet;
- begin
- result := TDerSet.FromVector(ReadVector(dIn), False);
- end;
- class function TAsn1InputStream.ReadTagNumber(const s: TStream;
- tag: Int32): Int32;
- var
- tagNo, b: Int32;
- begin
- tagNo := tag and $1F;
- //
- // with tagged object tag number is bottom 5 bits, or stored at the start of the content
- //
- if (tagNo = $1F) then
- begin
- tagNo := 0;
- b := TStreamSorter.ReadByte(s);
- // X.690-0207 8.1.2.4.2
- // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
- if ((b and $7F) = 0) then // Note: -1 will pass
- begin
- raise EIOCryptoLibException.CreateRes(@SCorruptedStreamInvalidTag);
- end;
- while ((b >= 0) and ((b and $80) <> 0)) do
- begin
- tagNo := tagNo or (b and $7F);
- tagNo := tagNo shl 7;
- b := TStreamSorter.ReadByte(s);
- end;
- if (b < 0) then
- begin
- raise EEndOfStreamCryptoLibException.CreateRes(@SEOFFound);
- end;
- tagNo := tagNo or (b and $7F);
- end;
- result := tagNo;
- end;
- { TDerOutputStream }
- constructor TDerOutputStream.Create(const os: TStream);
- begin
- Inherited Create(os);
- end;
- procedure TDerOutputStream.WriteEncoded(tag: Int32; first: Byte;
- const bytes: TCryptoLibByteArray);
- begin
- WriteByte(Byte(tag));
- WriteLength(System.length(bytes) + 1);
- WriteByte(first);
- Write(bytes[0], System.length(bytes));
- end;
- procedure TDerOutputStream.WriteEncoded(tag: Int32;
- const bytes: TCryptoLibByteArray);
- begin
- WriteByte(Byte(tag));
- WriteLength(System.length(bytes));
- if bytes <> Nil then
- begin
- Write(bytes[0], System.length(bytes));
- end;
- end;
- procedure TDerOutputStream.WriteEncoded(flags, tagNo: Int32;
- const bytes: TCryptoLibByteArray);
- begin
- WriteTag(flags, tagNo);
- WriteLength(System.length(bytes));
- Write(bytes[0], System.length(bytes));
- end;
- procedure TDerOutputStream.WriteEncoded(tag: Int32;
- const bytes: TCryptoLibByteArray; offset, length: Int32);
- begin
- WriteByte(Byte(tag));
- WriteLength(length);
- Write(bytes[offset], length);
- end;
- procedure TDerOutputStream.WriteLength(length: Int32);
- var
- Size, I: Int32;
- val: UInt32;
- begin
- if (length > 127) then
- begin
- Size := 1;
- val := UInt32(length);
- val := val shr 8;
- while (val <> 0) do
- begin
- System.Inc(Size);
- val := val shr 8;
- end;
- WriteByte(Byte(Size or $80));
- I := (Size - 1) * 8;
- while I >= 0 do
- begin
- WriteByte(Byte(TBits.Asr32(length, I)));
- System.Dec(I, 8);
- end;
- end
- else
- begin
- WriteByte(Byte(length));
- end;
- end;
- procedure TDerOutputStream.WriteNull;
- begin
- WriteByte(TAsn1Tags.Null);
- WriteByte($00);
- end;
- procedure TDerOutputStream.WriteObject(const obj: IAsn1Encodable);
- var
- asn1: IAsn1Object;
- begin
- if (obj = Nil) then
- begin
- WriteNull();
- end
- else
- begin
- asn1 := obj.ToAsn1Object();
- asn1.Encode(Self);
- end;
- end;
- procedure TDerOutputStream.WriteObject(const obj: IAsn1Object);
- begin
- if (obj = Nil) then
- begin
- WriteNull();
- end
- else
- begin
- obj.Encode(Self);
- end;
- end;
- procedure TDerOutputStream.WriteTag(flags, tagNo: Int32);
- var
- stack: TCryptoLibByteArray;
- Pos: Int32;
- begin
- if (tagNo < 31) then
- begin
- WriteByte(Byte(flags or tagNo));
- end
- else
- begin
- WriteByte(Byte(flags or $1F));
- if (tagNo < 128) then
- begin
- WriteByte(Byte(tagNo));
- end
- else
- begin
- System.SetLength(stack, 5);
- Pos := System.length(stack);
- System.Dec(Pos);
- stack[Pos] := Byte(tagNo and $7F);
- repeat
- tagNo := TBits.Asr32(tagNo, 7);
- System.Dec(Pos);
- stack[Pos] := Byte(tagNo and $7F or $80);
- until (not(tagNo > 127));
- Write(stack[Pos], System.length(stack) - Pos);
- end;
- end;
- end;
- { TAsn1OutputStream }
- constructor TAsn1OutputStream.Create(os: TStream);
- begin
- Inherited Create(os);
- end;
- { TBerOutputStream }
- constructor TBerOutputStream.Create(os: TStream);
- begin
- Inherited Create(os);
- end;
- { TConstructedOctetStream }
- constructor TConstructedOctetStream.Create(const parser: IAsn1StreamParser);
- begin
- Inherited Create();
- F_parser := parser;
- F_first := True;
- end;
- function TConstructedOctetStream.Read(buffer: TCryptoLibByteArray;
- offset, count: LongInt): LongInt;
- var
- s, aos: IAsn1OctetStringParser;
- totalRead, numRead: Int32;
- begin
- if (F_currentStream = Nil) then
- begin
- if (not F_first) then
- begin
- result := 0;
- Exit;
- end;
- if (not Supports(F_parser.ReadObject(), IAsn1OctetStringParser, s)) then
- begin
- result := 0;
- Exit;
- end;
- F_first := False;
- F_currentStream := s.GetOctetStream();
- end;
- totalRead := 0;
- while True do
- begin
- numRead := TStreamSorter.Read(F_currentStream, buffer, offset + totalRead,
- count - totalRead);
- if (numRead > 0) then
- begin
- totalRead := totalRead + numRead;
- if (totalRead = count) then
- begin
- result := totalRead;
- Exit;
- end;
- end
- else
- begin
- if (not Supports(F_parser.ReadObject(), IAsn1OctetStringParser, aos)) then
- begin
- F_currentStream := Nil;
- result := totalRead;
- Exit;
- end;
- F_currentStream := aos.GetOctetStream();
- end
- end;
- result := 0;
- end;
- function TConstructedOctetStream.ReadByte: Int32;
- var
- s, aos: IAsn1OctetStringParser;
- b: Int32;
- begin
- if (F_currentStream = Nil) then
- begin
- if (not F_first) then
- begin
- result := 0;
- Exit;
- end;
- if (not Supports(F_parser.ReadObject(), IAsn1OctetStringParser, s)) then
- begin
- result := 0;
- Exit;
- end;
- F_first := False;
- F_currentStream := s.GetOctetStream();
- end;
- while True do
- begin
- // b := F_currentStream.ReadByte();
- b := TStreamSorter.ReadByte(F_currentStream);
- if (b >= 0) then
- begin
- result := b;
- Exit;
- end;
- if (not Supports(F_parser.ReadObject(), IAsn1OctetStringParser, aos)) then
- begin
- F_currentStream := Nil;
- result := -1;
- Exit;
- end;
- F_currentStream := aos.GetOctetStream();
- end;
- result := 0;
- end;
- { TIndefiniteLengthInputStream }
- function TIndefiniteLengthInputStream.RequireByte: Int32;
- begin
- // result := F_in.ReadByte();
- result := TStreamSorter.ReadByte(F_in);
- if (result < 0) then
- begin
- // Corrupted stream
- raise EEndOfStreamCryptoLibException.Create('');
- end;
- end;
- function TIndefiniteLengthInputStream.CheckForEof: Boolean;
- var
- extra: Int32;
- begin
- if (F_lookAhead = $00) then
- begin
- extra := RequireByte();
- if (extra <> 0) then
- begin
- raise EIOCryptoLibException.CreateRes(@SMalformedContent);
- end;
- F_lookAhead := -1;
- SetParentEofDetect(True);
- result := True;
- Exit;
- end;
- result := F_lookAhead < 0;
- end;
- constructor TIndefiniteLengthInputStream.Create(inStream: TStream;
- limit: Int32);
- begin
- Inherited Create(inStream, limit);
- F_lookAhead := RequireByte();
- CheckForEof();
- end;
- function TIndefiniteLengthInputStream.Read(buffer: TCryptoLibByteArray;
- offset, count: LongInt): LongInt;
- var
- numRead: Int32;
- begin
- // Only use this optimisation if we aren't checking for 00
- if ((F_eofOn00) or (count <= 1)) then
- begin
- result := (Inherited Read(buffer, offset, count));
- Exit;
- end;
- if (F_lookAhead < 0) then
- begin
- result := 0;
- Exit;
- end;
- numRead := TStreamSorter.Read(F_in, buffer, offset + 1, count - 1);
- if (numRead <= 0) then
- begin
- // Corrupted stream
- raise EEndOfStreamCryptoLibException.Create('');
- end;
- buffer[offset] := Byte(F_lookAhead);
- F_lookAhead := RequireByte();
- result := numRead + 1;
- end;
- function TIndefiniteLengthInputStream.ReadByte: Int32;
- begin
- if (F_eofOn00 and CheckForEof()) then
- begin
- result := -1;
- Exit;
- end;
- result := F_lookAhead;
- F_lookAhead := RequireByte();
- end;
- procedure TIndefiniteLengthInputStream.SetEofOn00(eofOn00: Boolean);
- begin
- F_eofOn00 := eofOn00;
- if (F_eofOn00) then
- begin
- CheckForEof();
- end;
- end;
- { TCollectionUtilities }
- class function TCollectionUtilities.ToStructuredString
- (c: TCryptoLibGenericArray<IAsn1Encodable>): String;
- var
- sl: TStringList;
- idx: Int32;
- begin
- if (c = Nil) then
- begin
- result := '[]';
- Exit;
- end;
- sl := TStringList.Create();
- sl.LineBreak := '';
- try
- sl.Add('[');
- sl.Add((c[0] as TAsn1Encodable).ClassName);
- if System.length(c) > 1 then
- begin
- for idx := 1 to System.length(c) - 2 do
- begin
- sl.Add(', ');
- sl.Add((c[idx] as TAsn1Encodable).ClassName);
- end;
- end;
- sl.Add(']');
- result := sl.Text;
- finally
- sl.Free;
- end;
- end;
- { TAsn1Encodable }
- function TAsn1Encodable.Equals(const other: IAsn1Convertible): Boolean;
- var
- o1, o2: IAsn1Object;
- begin
- if (other = Self as IAsn1Convertible) then
- begin
- result := True;
- Exit;
- end;
- if (other = Nil) then
- begin
- result := False;
- Exit;
- end;
- o1 := ToAsn1Object();
- o2 := other.ToAsn1Object();
- result := ((o1 = o2) or ((o2 <> Nil) and (o1.CallAsn1Equals(o2))));
- end;
- function TAsn1Encodable.GetDerEncoded: TCryptoLibByteArray;
- begin
- try
- result := GetEncoded(Der);
- except
- on e: EIOCryptoLibException do
- begin
- result := Nil;
- end;
- end;
- end;
- function TAsn1Encodable.GetEncoded: TCryptoLibByteArray;
- var
- bOut: TMemoryStream;
- aOut: TAsn1OutputStream;
- begin
- bOut := TMemoryStream.Create();
- aOut := TAsn1OutputStream.Create(bOut);
- try
- aOut.WriteObject(Self as IAsn1Encodable);
- System.SetLength(result, bOut.Size);
- bOut.Position := 0;
- bOut.Read(result[0], System.length(result));
- finally
- bOut.Free;
- aOut.Free;
- end;
- end;
- function TAsn1Encodable.GetEncoded(const encoding: String): TCryptoLibByteArray;
- var
- bOut: TMemoryStream;
- dOut: TDerOutputStream;
- begin
- if (encoding = Der) then
- begin
- bOut := TMemoryStream.Create();
- dOut := TDerOutputStream.Create(bOut);
- try
- dOut.WriteObject(Self as IAsn1Encodable);
- System.SetLength(result, bOut.Size);
- bOut.Position := 0;
- bOut.Read(result[0], System.length(result));
- finally
- bOut.Free;
- dOut.Free;
- end;
- Exit;
- end;
- result := GetEncoded();
- end;
- function TAsn1Encodable.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
- {$ENDIF DELPHI}
- begin
- result := ToAsn1Object().CallAsn1GetHashCode();
- end;
- class function TAsn1Encodable.IsNullOrContainsNull
- (const data: TCryptoLibGenericArray<IAsn1Encodable>): Boolean;
- var
- count, I: Int32;
- begin
- if (data = Nil) then
- begin
- result := True;
- Exit;
- end;
- count := System.length(data);
- for I := 0 to System.Pred(count) do
- begin
- if (data[I] = Nil) then
- begin
- result := True;
- Exit;
- end;
- end;
- result := False;
- end;
- class function TAsn1Encodable.OpenArrayToDynamicArray
- (const data: array of IAsn1Encodable): TCryptoLibGenericArray<IAsn1Encodable>;
- var
- LDataLength, LIdx: Int32;
- begin
- LDataLength := System.length(data);
- System.SetLength(result, LDataLength);
- for LIdx := 0 to System.Pred(LDataLength) do
- begin
- result[LIdx] := data[LIdx];
- end;
- end;
- { TAsn1Object }
- function TAsn1Object.CallAsn1Equals(const obj: IAsn1Object): Boolean;
- begin
- result := Asn1Equals(obj);
- end;
- function TAsn1Object.CallAsn1GetHashCode: Int32;
- begin
- result := Asn1GetHashCode();
- end;
- class function TAsn1Object.FromByteArray(const data: TCryptoLibByteArray)
- : IAsn1Object;
- var
- asn1: TAsn1InputStream;
- input: TBytesStream;
- begin
- try
- // used TBytesStream here for one pass creation and population with byte array :)
- input := TBytesStream.Create(data);
- try
- asn1 := TAsn1InputStream.Create(input, System.length(data));
- try
- result := asn1.ReadObject();
- finally
- asn1.Free;
- end;
- if (input.Position <> input.Size) then
- begin
- raise EIOCryptoLibException.CreateRes(@SExtraData);
- end;
- finally
- input.Free;
- end;
- except
- on e: EInvalidCastCryptoLibException do
- begin
- raise EIOCryptoLibException.CreateRes(@SUnRecognizedObjectByteArray);
- end;
- end;
- end;
- class function TAsn1Object.FromStream(const inStr: TStream): IAsn1Object;
- var
- asn1Stream: TAsn1InputStream;
- begin
- asn1Stream := TAsn1InputStream.Create(inStr);
- try
- try
- result := asn1Stream.ReadObject();
- except
- on e: EInvalidCastCryptoLibException do
- begin
- raise EIOCryptoLibException.CreateRes(@SUnRecognizedObjectStream);
- end;
- end;
- finally
- asn1Stream.Free;
- end;
- end;
- function TAsn1Object.ToAsn1Object: IAsn1Object;
- begin
- result := Self as IAsn1Object;
- end;
- { TDerObjectIdentifier }
- function TDerObjectIdentifier.GetID: String;
- begin
- result := Fidentifier;
- end;
- function TDerObjectIdentifier.Asn1Equals(const asn1Object: IAsn1Object)
- : Boolean;
- var
- other: IDerObjectIdentifier;
- begin
- if (not Supports(asn1Object, IDerObjectIdentifier, other)) then
- begin
- result := False;
- Exit;
- end;
- result := ID = other.ID;
- end;
- function TDerObjectIdentifier.Asn1GetHashCode: Int32;
- begin
- result := TStringUtils.GetStringHashCode(Fidentifier);
- end;
- class procedure TDerObjectIdentifier.Boot;
- begin
- if FLock = Nil then
- begin
- FLock := TCriticalSection.Create;
- end;
- end;
- function TDerObjectIdentifier.Branch(const branchID: String)
- : IDerObjectIdentifier;
- begin
- result := TDerObjectIdentifier.Create(Self as IDerObjectIdentifier, branchID);
- end;
- constructor TDerObjectIdentifier.Create(const oid: IDerObjectIdentifier;
- const branchID: String);
- begin
- Inherited Create();
- if (not(IsValidBranchID(branchID, 1))) then
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SInvalidBranchId,
- [branchID]);
- end;
- Fidentifier := oid.ID + '.' + branchID;
- end;
- constructor TDerObjectIdentifier.Create(const identifier: String);
- begin
- Inherited Create();
- if (identifier = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SIdentifierNil);
- end;
- if (not(IsValidIdentifier(identifier))) then
- begin
- raise EFormatCryptoLibException.CreateResFmt(@SInvalidOID, [identifier]);
- end;
- Fidentifier := identifier;
- end;
- constructor TDerObjectIdentifier.Create(const bytes: TCryptoLibByteArray);
- begin
- Inherited Create();
- Fidentifier := MakeOidStringFromBytes(bytes);
- Fbody := System.Copy(bytes);
- end;
- function TDerObjectIdentifier.&on(const stem: IDerObjectIdentifier): Boolean;
- var
- LocalId, stemId: String;
- begin
- LocalId := ID;
- stemId := stem.ID;
- result := (System.length(LocalId) > System.length(stemId)) and
- (LocalId[System.length(stemId) + 1] = '.') and
- (AnsiStartsStr(stemId, LocalId));
- end;
- class constructor TDerObjectIdentifier.CreateDerObjectIdentifier;
- begin
- TDerObjectIdentifier.Boot;
- end;
- class destructor TDerObjectIdentifier.DestroyDerObjectIdentifier;
- begin
- FLock.Free;
- end;
- procedure TDerObjectIdentifier.DoOutput(const bOut: TMemoryStream);
- var
- tok: IOidTokenizer;
- token: String;
- first: Int32;
- begin
- tok := TOidTokenizer.Create(Fidentifier);
- token := tok.NextToken();
- first := StrToInt(token) * 40;
- token := tok.NextToken();
- if (System.length(token) <= 18) then
- begin
- WriteField(bOut, Int64(first + StrToInt64(token)));
- end
- else
- begin
- WriteField(bOut, TBigInteger.Create(token).Add(TBigInteger.ValueOf(first)));
- end;
- while (tok.HasMoreTokens) do
- begin
- token := tok.NextToken();
- if (System.length(token) <= 18) then
- begin
- WriteField(bOut, StrToInt64(token));
- end
- else
- begin
- WriteField(bOut, TBigInteger.Create(token));
- end;
- end;
- end;
- procedure TDerObjectIdentifier.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.ObjectIdentifier,
- GetBody());
- end;
- class function TDerObjectIdentifier.FromOctetString
- (const enc: TCryptoLibByteArray): IDerObjectIdentifier;
- var
- HashCode, first: Int32;
- entry: IDerObjectIdentifier;
- begin
- HashCode := TArrayUtils.GetArrayHashCode(enc);
- first := HashCode and 1023;
- FLock.Acquire;
- try
- entry := Fcache[first];
- if ((entry <> Nil) and (TArrayUtils.AreEqual(enc, entry.GetBody()))) then
- begin
- result := entry;
- Exit;
- end;
- Fcache[first] := TDerObjectIdentifier.Create(enc);
- result := Fcache[first];
- finally
- FLock.Release;
- end;
- end;
- function TDerObjectIdentifier.GetBody: TCryptoLibByteArray;
- var
- bOut: TMemoryStream;
- begin
- FLock.Acquire;
- try
- if (Fbody = Nil) then
- begin
- bOut := TMemoryStream.Create();
- try
- DoOutput(bOut);
- System.SetLength(Fbody, bOut.Size);
- bOut.Position := 0;
- bOut.Read(Fbody[0], System.length(Fbody));
- finally
- bOut.Free;
- end;
- end;
- finally
- FLock.Release;
- end;
- result := Fbody;
- end;
- class function TDerObjectIdentifier.GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IDerObjectIdentifier;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((explicitly) or (Supports(o, IDerObjectIdentifier))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := FromOctetString(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- class function TDerObjectIdentifier.GetInstance(const obj: TObject)
- : IDerObjectIdentifier;
- begin
- if ((obj = Nil) or (obj is TDerObjectIdentifier)) then
- begin
- result := obj as TDerObjectIdentifier;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerObjectIdentifier.GetInstance(const obj: TCryptoLibByteArray)
- : IDerObjectIdentifier;
- begin
- result := FromOctetString(obj);
- end;
- class function TDerObjectIdentifier.IsValidBranchID(const branchID: String;
- start: Int32): Boolean;
- var
- digitCount, Pos: Int32;
- ch: Char;
- begin
- digitCount := 0;
- Pos := System.length(branchID) + 1;
- System.Dec(Pos);
- while (Pos >= start) do
- begin
- ch := branchID[Pos];
- if (ch = '.') then
- begin
- if ((digitCount = 0) or ((digitCount > 1) and (branchID[Pos + 1] = '0')))
- then
- begin
- result := False;
- Exit;
- end;
- digitCount := 0;
- end
- else if (CharInSet(ch, ['0' .. '9'])) then
- begin
- System.Inc(digitCount);
- end
- else
- begin
- result := False;
- Exit;
- end;
- System.Dec(Pos);
- end;
- if ((digitCount = 0) or ((digitCount > 1) and (branchID[Pos + 1] = '0'))) then
- begin
- result := False;
- Exit;
- end;
- result := True;
- end;
- class function TDerObjectIdentifier.IsValidIdentifier(const identifier
- : String): Boolean;
- var
- first: Char;
- begin
- if ((System.length(identifier) < 3) or (identifier[2] <> '.')) then
- begin
- result := False;
- Exit;
- end;
- first := identifier[1];
- if (not CharInSet(first, ['0' .. '2'])) then
- begin
- result := False;
- Exit;
- end;
- result := IsValidBranchID(identifier, 3);
- end;
- class function TDerObjectIdentifier.MakeOidStringFromBytes
- (const bytes: TCryptoLibByteArray): String;
- var
- objId: TStringList;
- Value: Int64;
- bigValue: TBigInteger;
- first: Boolean;
- I, b: Int32;
- begin
- Value := 0;
- bigValue := Default (TBigInteger);
- first := True;
- objId := TStringList.Create();
- objId.LineBreak := '';
- try
- I := 0;
- while I <> System.length(bytes) do
- begin
- b := Int32(bytes[I]);
- if (Value <= LONG_LIMIT) then
- begin
- Value := Value + (b and $7F);
- if ((b and $80) = 0) then // end of number reached
- begin
- if (first) then
- begin
- if (Value < 40) then
- begin
- objId.Add('0');
- end
- else if (Value < 80) then
- begin
- objId.Add('1');
- Value := Value - 40;
- end
- else
- begin
- objId.Add('2');
- Value := Value - 80;
- end;
- first := False;
- end;
- objId.Add('.');
- objId.Add(IntToStr(Value));
- Value := 0;
- end
- else
- begin
- Value := Value shl 7;
- end;
- end
- else
- begin
- if (not bigValue.IsInitialized) then
- begin
- bigValue := TBigInteger.ValueOf(Value);
- end;
- bigValue := bigValue.&Or(TBigInteger.ValueOf(b and $7F));
- if ((b and $80) = 0) then
- begin
- if (first) then
- begin
- objId.Add('2');
- bigValue := bigValue.Subtract(TBigInteger.ValueOf(80));
- first := False;
- end;
- objId.Add('.');
- objId.Add(bigValue.ToString());
- bigValue := Default (TBigInteger);
- Value := 0;
- end
- else
- begin
- bigValue := bigValue.ShiftLeft(7);
- end
- end;
- System.Inc(I);
- end;
- result := objId.Text;
- finally
- objId.Free;
- end;
- end;
- function TDerObjectIdentifier.ToString: String;
- begin
- result := ID;
- end;
- procedure TDerObjectIdentifier.WriteField(const outputStream: TStream;
- const fieldValue: TBigInteger);
- var
- byteCount, I: Int32;
- tmpValue: TBigInteger;
- tmp: TCryptoLibByteArray;
- begin
- byteCount := (fieldValue.BitLength + 6) div 7;
- if (byteCount = 0) then
- begin
- outputStream.WriteByte(0);
- end
- else
- begin
- tmpValue := fieldValue;
- System.SetLength(tmp, byteCount);
- I := byteCount - 1;
- while I >= 0 do
- begin
- tmp[I] := Byte((tmpValue.Int32Value and $7F) or $80);
- tmpValue := tmpValue.ShiftRight(7);
- System.Dec(I);
- end;
- tmp[byteCount - 1] := tmp[byteCount - 1] and $7F;
- outputStream.Write(tmp[0], System.length(tmp));
- end;
- end;
- procedure TDerObjectIdentifier.WriteField(const outputStream: TStream;
- fieldValue: Int64);
- var
- tempRes: TCryptoLibByteArray;
- Pos: Int32;
- begin
- System.SetLength(tempRes, 9);
- Pos := 8;
- tempRes[Pos] := Byte(fieldValue and $7F);
- while (fieldValue >= (Int64(1) shl 7)) do
- begin
- fieldValue := TBits.Asr64(fieldValue, 7);
- System.Dec(Pos);
- tempRes[Pos] := Byte((fieldValue and $7F) or $80);
- end;
- outputStream.Write(tempRes[Pos], 9 - Pos);
- end;
- { TAsn1EncodableVector }
- procedure TAsn1EncodableVector.Add(const objs: array of IAsn1Encodable);
- var
- obj: IAsn1Encodable;
- begin
- for obj in objs do
- begin
- Add(obj);
- end;
- end;
- procedure TAsn1EncodableVector.Add(const element: IAsn1Encodable);
- var
- capacity, minCapacity: Int32;
- begin
- if (element = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SElementNil);
- end;
- capacity := System.length(FElements);
- minCapacity := FElementCount + 1;
- if ((minCapacity > capacity) or FCopyOnWrite) then
- begin
- Reallocate(minCapacity);
- end;
- FElements[FElementCount] := element;
- FElementCount := minCapacity;
- end;
- procedure TAsn1EncodableVector.AddAll(const other: IAsn1EncodableVector);
- var
- otherElementCount, capacity, minCapacity, I: Int32;
- otherElement: IAsn1Encodable;
- begin
- if (other = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SOtherNil);
- end;
- otherElementCount := other.count;
- if (otherElementCount < 1) then
- begin
- Exit;
- end;
- capacity := System.length(FElements);
- minCapacity := FElementCount + otherElementCount;
- if ((minCapacity > capacity) or FCopyOnWrite) then
- begin
- Reallocate(minCapacity);
- end;
- I := 0;
- repeat
- otherElement := other[I];
- if (otherElement = Nil) then
- begin
- raise ENullReferenceCryptoLibException.CreateRes(@SOtherElementsNil);
- end;
- FElements[FElementCount + I] := otherElement;
- System.Inc(I);
- until not(I < otherElementCount);
- FElementCount := minCapacity;
- end;
- procedure TAsn1EncodableVector.AddOptional(const objs: array of IAsn1Encodable);
- var
- obj: IAsn1Encodable;
- begin
- if (System.length(objs) <> 0) then
- begin
- for obj in objs do
- begin
- if (obj <> Nil) then
- begin
- Add(obj);
- end;
- end;
- end;
- end;
- procedure TAsn1EncodableVector.AddOptionalTagged(isExplicit: Boolean;
- tagNo: Int32; const obj: IAsn1Encodable);
- begin
- if (obj <> Nil) then
- begin
- Add(TDerTaggedObject.Create(isExplicit, tagNo, obj) as IDerTaggedObject);
- end;
- end;
- function TAsn1EncodableVector.CopyElements
- : TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- if (FElementCount = 0) then
- begin
- result := EmptyElements;
- Exit;
- end;
- result := System.Copy(FElements, 0, FElementCount);
- System.SetLength(result, FElementCount);
- end;
- constructor TAsn1EncodableVector.Create(const v: array of IAsn1Encodable);
- begin
- inherited Create();
- Add(v);
- end;
- constructor TAsn1EncodableVector.Create(initialCapacity: Int32);
- begin
- Inherited Create();
- if (initialCapacity < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInitialCapacityNegative);
- end;
- if (initialCapacity = 0) then
- begin
- FElements := EmptyElements;
- end
- else
- begin
- System.SetLength(FElements, initialCapacity);
- end;
- FElementCount := 0;
- FCopyOnWrite := False;
- end;
- constructor TAsn1EncodableVector.Create();
- begin
- Create(DefaultCapacity);
- end;
- destructor TAsn1EncodableVector.Destroy;
- begin
- inherited Destroy;
- end;
- class function TAsn1EncodableVector.FromEnumerable
- (const e: TList<IAsn1Encodable>): IAsn1EncodableVector;
- var
- v: IAsn1EncodableVector;
- obj: IAsn1Encodable;
- begin
- v := TAsn1EncodableVector.Create();
- for obj in e do
- begin
- v.Add(obj);
- end;
- result := v;
- end;
- function TAsn1EncodableVector.GetCount: Int32;
- begin
- result := FElementCount;
- end;
- class function TAsn1EncodableVector.GetEmptyElements
- : TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := Nil;
- end;
- function TAsn1EncodableVector.GetEnumerable
- : TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := CopyElements();
- end;
- function TAsn1EncodableVector.GetSelf(Index: Int32): IAsn1Encodable;
- begin
- if (Index >= FElementCount) then
- begin
- raise EIndexOutOfRangeCryptoLibException.CreateResFmt(@SIndexOutOfRange,
- [Index, FElementCount]);
- end;
- result := FElements[Index];
- end;
- procedure TAsn1EncodableVector.Reallocate(minCapacity: Int32);
- var
- oldCapacity, newCapacity: Int32;
- LocalCopy: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- oldCapacity := System.length(FElements);
- newCapacity := Max(oldCapacity, minCapacity + (TBits.Asr32(minCapacity, 1)));
- LocalCopy := System.Copy(FElements, 0, FElementCount);
- System.SetLength(LocalCopy, newCapacity);
- FElements := LocalCopy;
- FCopyOnWrite := False;
- end;
- function TAsn1EncodableVector.TakeElements
- : TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- if (FElementCount = 0) then
- begin
- result := EmptyElements;
- Exit;
- end;
- if (System.length(FElements) = FElementCount) then
- begin
- FCopyOnWrite := True;
- result := FElements;
- Exit;
- end;
- result := System.Copy(FElements, 0, FElementCount);
- System.SetLength(result, FElementCount);
- end;
- class function TAsn1EncodableVector.CloneElements(const elements
- : TCryptoLibGenericArray<IAsn1Encodable>)
- : TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- if System.length(elements) < 1 then
- begin
- result := EmptyElements;
- end
- else
- begin
- result := System.Copy(elements);
- end;
- end;
- { TAsn1Generator }
- constructor TAsn1Generator.Create(outStream: TStream);
- begin
- F_out := outStream;
- end;
- function TAsn1Generator.GetOut: TStream;
- begin
- result := F_out;
- end;
- { TAsn1Null }
- function TAsn1Null.ToString: String;
- begin
- result := 'NULL';
- end;
- { TAsn1OctetString }
- function TAsn1OctetString.GetStr: TCryptoLibByteArray;
- begin
- result := FStr;
- end;
- function TAsn1OctetString.GetParser: IAsn1OctetStringParser;
- begin
- result := Self as IAsn1OctetStringParser;
- end;
- constructor TAsn1OctetString.Create(const Str: TCryptoLibByteArray);
- begin
- Inherited Create();
- if (Str = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- function TAsn1OctetString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerOctetString;
- begin
- if (not Supports(asn1Object, IDerOctetString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(GetOctets(), other.GetOctets());
- end;
- function TAsn1OctetString.Asn1GetHashCode: Int32;
- begin
- result := TArrayUtils.GetArrayHashCode(GetOctets());
- end;
- constructor TAsn1OctetString.Create(const obj: IAsn1Encodable);
- begin
- Inherited Create();
- try
- FStr := obj.GetEncoded(TAsn1Encodable.Der);
- except
- on e: EIOCryptoLibException do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SProcessingError,
- [e.Message]);
- end;
- end;
- end;
- class function TAsn1OctetString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IAsn1OctetString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IAsn1OctetString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TBerOctetString.FromSequence
- (TAsn1Sequence.GetInstance(o as TAsn1Object));
- end;
- class function TAsn1OctetString.GetInstance(const obj: TObject)
- : IAsn1OctetString;
- var
- asn1TaggedObject: IAsn1TaggedObject;
- begin
- if ((obj = Nil) or (obj is TAsn1OctetString)) then
- begin
- result := obj as TAsn1OctetString;
- Exit;
- end;
- // TODO: this needs to be deleted in V2
- if Supports(obj, IAsn1TaggedObject, asn1TaggedObject) then
- begin
- result := GetInstance(asn1TaggedObject.GetObject() as TAsn1Object);
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- function TAsn1OctetString.GetOctets: TCryptoLibByteArray;
- begin
- result := Str;
- end;
- function TAsn1OctetString.GetOctetStream: TStream;
- begin
- // used TBytesStream here for one pass creation and population with byte array :)
- result := TBytesStream.Create(Str);
- end;
- function TAsn1OctetString.ToString: String;
- begin
- result := '#' + THex.Encode(Str);
- end;
- { TAsn1Sequence }
- function TAsn1Sequence.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- that: IAsn1Sequence;
- o1, o2: IAsn1Object;
- I, LCount: Int32;
- begin
- that := asn1Object as IAsn1Sequence;
- if (that = Nil) then
- begin
- result := False;
- Exit;
- end;
- LCount := count;
- if (that.count <> LCount) then
- begin
- result := False;
- Exit;
- end;
- for I := 0 to System.Pred(LCount) do
- begin
- o1 := FElements[I].ToAsn1Object();
- o2 := that.elements[I].ToAsn1Object();
- if ((o1 <> o2) and (not o1.CallAsn1Equals(o2))) then
- begin
- result := False;
- Exit;
- end;
- end;
- result := True;
- end;
- function TAsn1Sequence.Asn1GetHashCode: Int32;
- var
- hc, I: Int32;
- begin
- I := System.length(FElements);
- hc := I + 1;
- System.Dec(I);
- while (I >= 0) do
- begin
- hc := hc * 257;
- hc := hc xor (FElements[I].ToAsn1Object().CallAsn1GetHashCode());
- System.Dec(I);
- end;
- result := hc;
- end;
- constructor TAsn1Sequence.Create();
- begin
- inherited Create();
- FElements := TAsn1EncodableVector.EmptyElements;
- end;
- constructor TAsn1Sequence.Create(const element: IAsn1Encodable);
- begin
- Inherited Create();
- if (element = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SElementNil);
- end;
- FElements := TCryptoLibGenericArray<IAsn1Encodable>.Create(element);
- end;
- constructor TAsn1Sequence.Create(const elementVector: IAsn1EncodableVector);
- begin
- Inherited Create();
- if (elementVector = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SElementVectorNil);
- end;
- FElements := elementVector.TakeElements();
- end;
- constructor TAsn1Sequence.Create(const elements: array of IAsn1Encodable);
- var
- LElementsCopy: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- Inherited Create();
- LElementsCopy := OpenArrayToDynamicArray(elements);
- if (TAsn1Encodable.IsNullOrContainsNull(LElementsCopy)) then
- begin
- raise ENullReferenceCryptoLibException.CreateRes(@SElementsNil);
- end;
- FElements := TAsn1EncodableVector.CloneElements(LElementsCopy);
- end;
- destructor TAsn1Sequence.Destroy;
- begin
- inherited Destroy;
- end;
- function TAsn1Sequence.GetCount: Int32;
- begin
- result := System.length(FElements);
- end;
- function TAsn1Sequence.GetElements: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := FElements;
- end;
- function TAsn1Sequence.GetEnumerable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := FElements;
- end;
- class function TAsn1Sequence.GetInstance(const obj: TObject): IAsn1Sequence;
- var
- primitive: IAsn1Object;
- Sequence: IAsn1Sequence;
- res: IAsn1SequenceParser;
- begin
- if ((obj = Nil) or (obj is TAsn1Sequence)) then
- begin
- result := obj as TAsn1Sequence;
- Exit;
- end;
- if (Supports(obj, IAsn1SequenceParser, res)) then
- begin
- result := TAsn1Sequence.GetInstance(res.ToAsn1Object() as TAsn1Object);
- Exit;
- end;
- if (obj is TAsn1Encodable) then
- begin
- primitive := (obj as TAsn1Encodable).ToAsn1Object();
- if (Supports(primitive, IAsn1Sequence, Sequence)) then
- begin
- result := Sequence;
- Exit;
- end;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SUnknownObject,
- [obj.ClassName]);
- end;
- class function TAsn1Sequence.GetInstance(const obj: TCryptoLibByteArray)
- : IAsn1Sequence;
- begin
- try
- result := TAsn1Sequence.GetInstance(FromByteArray(obj) as TAsn1Object);
- except
- on e: EIOCryptoLibException do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SInvalidSequence,
- [e.Message]);
- end;
- end;
- end;
- class function TAsn1Sequence.GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1Sequence;
- var
- inner: IAsn1Object;
- Sequence: IAsn1Sequence;
- begin
- inner := obj.GetObject();
- if (explicitly) then
- begin
- if (not(obj.isExplicit())) then
- raise EArgumentCryptoLibException.CreateRes(@SInvalidObject);
- result := inner as IAsn1Sequence;
- Exit;
- end;
- //
- // constructed object which appears to be explicitly tagged
- // when it should be implicit means we have to add the
- // surrounding sequence.
- //
- if (obj.isExplicit()) then
- begin
- if (Supports(obj, IBerTaggedObject)) then
- begin
- result := TBerSequence.Create(inner);
- Exit;
- end;
- result := TDerSequence.Create(inner);
- Exit;
- end;
- if (Supports(inner, IAsn1Sequence, Sequence)) then
- begin
- result := Sequence;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SUnknownObject,
- [(obj as TAsn1TaggedObject).ClassName]);
- end;
- function TAsn1Sequence.GetParser: IAsn1SequenceParser;
- begin
- result := TAsn1SequenceParserImpl.Create(Self as IAsn1Sequence);
- end;
- function TAsn1Sequence.GetSelf(Index: Int32): IAsn1Encodable;
- begin
- result := FElements[Index];
- end;
- function TAsn1Sequence.ToArray: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := TAsn1EncodableVector.CloneElements(FElements);
- end;
- function TAsn1Sequence.ToString: String;
- begin
- result := TCollectionUtilities.ToStructuredString(FElements);
- end;
- { TAsn1Sequence.TAsn1SequenceParserImpl }
- constructor TAsn1Sequence.TAsn1SequenceParserImpl.Create
- (const outer: IAsn1Sequence);
- begin
- inherited Create();
- Fouter := outer;
- Fmax := outer.count;
- end;
- function TAsn1Sequence.TAsn1SequenceParserImpl.ReadObject: IAsn1Convertible;
- var
- obj: IAsn1Encodable;
- Sequence: IAsn1Sequence;
- asn1Set: IAsn1Set;
- begin
- if (Findex = Fmax) then
- begin
- result := Nil;
- Exit;
- end;
- obj := Fouter[Findex];
- System.Inc(Findex);
- if (Supports(obj, IAsn1Sequence, Sequence)) then
- begin
- result := Sequence.parser;
- Exit;
- end;
- if (Supports(obj, IAsn1Set, asn1Set)) then
- begin
- result := asn1Set.parser;
- Exit;
- end;
- // NB: Asn1OctetString implements Asn1OctetStringParser directly
- // if (obj is Asn1OctetString)
- // return ((Asn1OctetString)obj).Parser;
- result := obj;
- end;
- function TAsn1Sequence.TAsn1SequenceParserImpl.ToAsn1Object: IAsn1Object;
- begin
- result := Fouter;
- end;
- { TDerOctetString }
- constructor TDerOctetString.Create(const Str: TCryptoLibByteArray);
- begin
- Inherited Create(Str);
- end;
- constructor TDerOctetString.Create(const obj: IAsn1Encodable);
- begin
- Inherited Create(obj);
- end;
- destructor TDerOctetString.Destroy;
- begin
- inherited Destroy;
- end;
- procedure TDerOctetString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.OctetString, Str);
- end;
- class procedure TDerOctetString.Encode(const derOut: TDerOutputStream;
- const bytes: TCryptoLibByteArray; offset, length: Int32);
- begin
- derOut.WriteEncoded(TAsn1Tags.OctetString, bytes, offset, length);
- end;
- { TBerOctetString }
- constructor TBerOctetString.Create(const octets: TList<IDerOctetString>);
- begin
- Inherited Create(ToBytes(octets));
- Focts := octets;
- end;
- constructor TBerOctetString.Create(const Str: TCryptoLibByteArray);
- begin
- Inherited Create(Str);
- end;
- constructor TBerOctetString.Create(const obj: IAsn1Encodable);
- begin
- Inherited Create(obj.ToAsn1Object());
- end;
- destructor TBerOctetString.Destroy;
- begin
- Focts.Free;
- inherited Destroy;
- end;
- constructor TBerOctetString.Create(const obj: IAsn1Object);
- begin
- Inherited Create(obj);
- end;
- procedure TBerOctetString.Encode(const derOut: TStream);
- var
- oct: IDerOctetString;
- LListIDerOctetString: TCryptoLibGenericArray<IDerOctetString>;
- begin
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream).WriteByte(TAsn1Tags.Constructed or
- TAsn1Tags.OctetString);
- (derOut as TDerOutputStream).WriteByte($80);
- //
- // write out the octet array
- //
- LListIDerOctetString := Self.GetEnumerable;
- for oct in LListIDerOctetString do
- begin
- (derOut as TDerOutputStream).WriteObject(oct);
- end;
- (derOut as TDerOutputStream).WriteByte($00);
- (derOut as TDerOutputStream).WriteByte($00);
- end
- else
- begin
- (Inherited Encode(derOut));
- end;
- end;
- class function TBerOctetString.FromSequence(const seq: IAsn1Sequence)
- : IBerOctetString;
- var
- v: TList<IDerOctetString>;
- obj: IAsn1Encodable;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- v := TList<IDerOctetString>.Create();
- LListAsn1Encodable := seq.GetEnumerable;
- for obj in LListAsn1Encodable do
- begin
- v.Add(obj as IDerOctetString);
- end;
- result := TBerOctetString.Create(v);
- end;
- function TBerOctetString.GenerateOcts: TList<IDerOctetString>;
- var
- I, endPoint: Int32;
- nStr: TCryptoLibByteArray;
- begin
- result := TList<IDerOctetString>.Create();
- I := 0;
- while I < System.length(Str) do
- begin
- endPoint := Min(System.length(Str), I + MaxLength);
- System.SetLength(nStr, endPoint - I);
- System.Move(Str[I], nStr[0], System.length(nStr) * System.SizeOf(Byte));
- result.Add(TDerOctetString.Create(nStr) as IDerOctetString);
- System.Inc(I, MaxLength);
- end;
- end;
- function TBerOctetString.GetEnumerable: TCryptoLibGenericArray<IDerOctetString>;
- var
- LList: TList<IDerOctetString>;
- begin
- if (Focts = Nil) then
- begin
- LList := GenerateOcts();
- try
- result := LList.ToArray;
- Exit;
- finally
- LList.Free;
- end;
- end;
- result := Focts.ToArray;
- end;
- function TBerOctetString.GetOctets: TCryptoLibByteArray;
- begin
- result := Str;
- end;
- class function TBerOctetString.ToBytes(octs: TList<IDerOctetString>)
- : TCryptoLibByteArray;
- var
- bOut: TMemoryStream;
- o: IDerOctetString;
- octets: TCryptoLibByteArray;
- begin
- bOut := TMemoryStream.Create();
- try
- for o in octs do
- begin
- octets := o.GetOctets();
- bOut.Write(octets[0], System.length(octets));
- end;
- System.SetLength(result, bOut.Size);
- bOut.Position := 0;
- bOut.Read(result[0], bOut.Size);
- finally
- bOut.Free;
- end;
- end;
- { TDerNull }
- function TDerNull.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- begin
- result := Supports(asn1Object, IDerNull);
- end;
- function TDerNull.Asn1GetHashCode: Int32;
- begin
- result := -1;
- end;
- {$IFNDEF _FIXINSIGHT_}
- constructor TDerNull.Create(dummy: Int32);
- begin
- Inherited Create();
- end;
- {$ENDIF}
- procedure TDerNull.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Null, ZeroBytes);
- end;
- class function TDerNull.GetInstance: IDerNull;
- begin
- result := TDerNull.Create(0);
- end;
- { TDerSequence }
- class function TDerSequence.GetEmpty: IDerSequence;
- begin
- result := TDerSequence.Create();
- end;
- constructor TDerSequence.Create(const element: IAsn1Encodable);
- begin
- Inherited Create(element);
- end;
- constructor TDerSequence.Create;
- begin
- Inherited Create();
- end;
- constructor TDerSequence.Create(const elementVector: IAsn1EncodableVector);
- begin
- Inherited Create(elementVector);
- end;
- constructor TDerSequence.Create(const elements: array of IAsn1Encodable);
- begin
- Inherited Create(elements);
- end;
- destructor TDerSequence.Destroy;
- begin
- inherited Destroy;
- end;
- procedure TDerSequence.Encode(const derOut: TStream);
- var
- bOut: TMemoryStream;
- dOut: TDerOutputStream;
- obj: IAsn1Encodable;
- bytes: TCryptoLibByteArray;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- // TODO Intermediate buffer could be avoided if we could calculate expected length
- bOut := TMemoryStream.Create();
- dOut := TDerOutputStream.Create(bOut);
- try
- LListAsn1Encodable := Self.GetEnumerable;
- for obj in LListAsn1Encodable do
- begin
- dOut.WriteObject(obj);
- end;
- System.SetLength(bytes, bOut.Size);
- bOut.Position := 0;
- bOut.Read(bytes[0], bOut.Size);
- finally
- bOut.Free;
- dOut.Free;
- end;
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Sequence or
- TAsn1Tags.Constructed, bytes);
- end;
- class function TDerSequence.FromVector(const elementVector
- : IAsn1EncodableVector): IDerSequence;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TDerSequence.Create(elementVector);
- end;
- end;
- { TBerSequence }
- class function TBerSequence.GetEmpty: IBerSequence;
- begin
- result := TBerSequence.Create();
- end;
- constructor TBerSequence.Create(const element: IAsn1Encodable);
- begin
- Inherited Create(element);
- end;
- constructor TBerSequence.Create;
- begin
- Inherited Create();
- end;
- constructor TBerSequence.Create(const elementVector: IAsn1EncodableVector);
- begin
- Inherited Create(elementVector);
- end;
- destructor TBerSequence.Destroy;
- begin
- inherited Destroy;
- end;
- constructor TBerSequence.Create(const elements: array of IAsn1Encodable);
- begin
- Inherited Create(elements);
- end;
- procedure TBerSequence.Encode(const derOut: TStream);
- var
- o: IAsn1Encodable;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream).WriteByte(TAsn1Tags.Sequence or
- TAsn1Tags.Constructed);
- (derOut as TDerOutputStream).WriteByte($80);
- LListAsn1Encodable := Self.GetEnumerable;
- for o in LListAsn1Encodable do
- begin
- (derOut as TDerOutputStream).WriteObject(o);
- end;
- (derOut as TDerOutputStream).WriteByte($00);
- (derOut as TDerOutputStream).WriteByte($00);
- end
- else
- begin
- (Inherited Encode(derOut));
- end;
- end;
- class function TBerSequence.FromVector(const elementVector
- : IAsn1EncodableVector): IBerSequence;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TBerSequence.Create(elementVector);
- end;
- end;
- { TAsn1TaggedObject }
- function TAsn1TaggedObject.GetObject: IAsn1Object;
- begin
- if (Fobj <> Nil) then
- begin
- result := Fobj.ToAsn1Object();
- Exit;
- end;
- result := Nil;
- end;
- function TAsn1TaggedObject.GetTagNo: Int32;
- begin
- result := FtagNo;
- end;
- function TAsn1TaggedObject.Getexplicitly: Boolean;
- begin
- result := Fexplicitly;
- end;
- function TAsn1TaggedObject.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IAsn1TaggedObject;
- begin
- if (not Supports(asn1Object, IAsn1TaggedObject, other)) then
- begin
- result := False;
- Exit;
- end;
- result := ((tagNo = other.tagNo) and
- // TODO Should this be part of equality?
- (explicitly = other.explicitly)) and
- (GetObject().Equals(other.GetObject()));
- end;
- function TAsn1TaggedObject.Asn1GetHashCode: Int32;
- var
- code: Int32;
- begin
- code := Abs(tagNo);
- // TODO: actually this is wrong - the problem is that a re-encoded
- // object may end up with a different hashCode due to implicit
- // tagging. As implicit tagging is ambiguous if a sequence is involved
- // it seems the only correct method for both equals and hashCode is to
- // compare the encodings...
- // code := code xor explicitly.GetHashCode();
- if (Fobj <> Nil) then
- begin
- code := code xor Fobj.GetHashCode();
- end;
- result := code;
- end;
- constructor TAsn1TaggedObject.Create(tagNo: Int32; const obj: IAsn1Encodable);
- begin
- Inherited Create();
- Fexplicitly := True;
- FtagNo := tagNo;
- Fobj := obj;
- end;
- constructor TAsn1TaggedObject.Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable);
- begin
- Inherited Create();
- // IAsn1Choice marker interface 'insists' on explicit tagging
- Fexplicitly := explicitly or (Supports(obj, IAsn1Choice));
- FtagNo := tagNo;
- Fobj := obj;
- end;
- class function TAsn1TaggedObject.GetInstance(obj: TObject): IAsn1TaggedObject;
- begin
- if ((obj = Nil) or (obj is TAsn1TaggedObject)) then
- begin
- result := obj as TAsn1TaggedObject;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SUnknownObject,
- [obj.ClassName]);
- end;
- function TAsn1TaggedObject.Getobj: IAsn1Encodable;
- begin
- result := Fobj;
- end;
- class function TAsn1TaggedObject.GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1TaggedObject;
- begin
- if (explicitly) then
- begin
- result := GetInstance(obj.GetObject() as TAsn1Object);
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateRes(@SImplicitObject);
- end;
- function TAsn1TaggedObject.GetObjectParser(tag: Int32; isExplicit: Boolean)
- : IAsn1Convertible;
- begin
- case tag of
- TAsn1Tags.&Set:
- begin
- result := TAsn1Set.GetInstance(Self as IAsn1TaggedObject,
- isExplicit).parser;
- Exit;
- end;
- TAsn1Tags.Sequence:
- begin
- result := TAsn1Sequence.GetInstance(Self as IAsn1TaggedObject,
- isExplicit).parser;
- Exit;
- end;
- TAsn1Tags.OctetString:
- begin
- result := TAsn1OctetString.GetInstance(Self as IAsn1TaggedObject,
- isExplicit).parser;
- Exit;
- end;
- end;
- if (isExplicit) then
- begin
- result := GetObject();
- Exit;
- end;
- raise ENotImplementedCryptoLibException.CreateResFmt(@SImplicitTag, [tag]);
- end;
- class function TAsn1TaggedObject.IsConstructed(isExplicit: Boolean;
- const obj: IAsn1Object): Boolean;
- var
- Tagged: IAsn1TaggedObject;
- begin
- if ((isExplicit) or (Supports(obj, IAsn1Sequence)) or
- (Supports(obj, IAsn1Set))) then
- begin
- result := True;
- Exit;
- end;
- if (not Supports(obj, IAsn1TaggedObject, Tagged)) then
- begin
- result := False;
- Exit;
- end;
- result := IsConstructed(Tagged.isExplicit(), Tagged.GetObject());
- end;
- function TAsn1TaggedObject.IsEmpty: Boolean;
- begin
- result := False; // empty;
- end;
- function TAsn1TaggedObject.isExplicit: Boolean;
- begin
- result := Fexplicitly;
- end;
- function TAsn1TaggedObject.ToString: String;
- begin
- result := '[' + IntToStr(tagNo) + ']' + (Fobj as TAsn1Encodable).ClassName;
- end;
- { TAsn1Set }
- function TAsn1Set.GetDerEncoded(const obj: IAsn1Encodable): TCryptoLibByteArray;
- begin
- try
- result := obj.GetEncoded(Der);
- except
- on e: EIOCryptoLibException do
- begin
- raise EInvalidArgumentCryptoLibException.CreateRes(@SObjectEncodeError);
- end;
- end;
- end;
- function TAsn1Set.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- that: IAsn1Set;
- o1, o2: IAsn1Object;
- idx, LCount: Int32;
- begin
- if (not Supports(asn1Object, IAsn1Set, that)) then
- begin
- result := False;
- Exit;
- end;
- LCount := count;
- if (that.count <> LCount) then
- begin
- result := False;
- Exit;
- end;
- for idx := 0 to System.Pred(LCount) do
- begin
- o1 := FElements[idx].ToAsn1Object();
- o2 := that.elements[idx].ToAsn1Object();
- if ((o1 <> o2) and (not o1.CallAsn1Equals(o2))) then
- begin
- result := False;
- Exit;
- end;
- end;
- result := True;
- end;
- function TAsn1Set.Asn1GetHashCode: Int32;
- var
- hc, I: Int32;
- begin
- I := System.length(FElements);
- hc := I + 1;
- System.Dec(I);
- while (I >= 0) do
- begin
- hc := hc * 257;
- hc := hc xor FElements[I].ToAsn1Object().CallAsn1GetHashCode();
- System.Dec(I);
- end;
- result := hc;
- end;
- constructor TAsn1Set.Create();
- begin
- Inherited Create();
- FElements := TAsn1EncodableVector.EmptyElements;
- end;
- constructor TAsn1Set.Create(const element: IAsn1Encodable);
- begin
- Inherited Create();
- if (element = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SElementNil);
- end;
- FElements := TCryptoLibGenericArray<IAsn1Encodable>.Create(element);
- end;
- constructor TAsn1Set.Create(const elementVector: IAsn1EncodableVector);
- begin
- Inherited Create();
- if (elementVector = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SElementVectorNil);
- end;
- FElements := elementVector.TakeElements();
- end;
- constructor TAsn1Set.Create(const elements: array of IAsn1Encodable);
- var
- LElementsCopy: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- Inherited Create();
- LElementsCopy := OpenArrayToDynamicArray(elements);
- if (TAsn1Encodable.IsNullOrContainsNull(LElementsCopy)) then
- begin
- raise ENullReferenceCryptoLibException.CreateRes(@SElementsNil);
- end;
- FElements := TAsn1EncodableVector.CloneElements(LElementsCopy);
- end;
- destructor TAsn1Set.Destroy;
- begin
- inherited Destroy;
- end;
- function TAsn1Set.GetCount: Int32;
- begin
- result := System.length(FElements);
- end;
- function TAsn1Set.GetElements: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := FElements;
- end;
- function TAsn1Set.GetEnumerable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := FElements;
- end;
- class function TAsn1Set.GetInstance(const obj: TCryptoLibByteArray): IAsn1Set;
- begin
- try
- result := TAsn1Set.GetInstance(FromByteArray(obj) as TAsn1Object);
- except
- on e: EIOCryptoLibException do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SInvalidSequence,
- [e.Message]);
- end;
- end;
- end;
- class function TAsn1Set.GetInstance(const obj: IAsn1TaggedObject;
- explicitly: Boolean): IAsn1Set;
- var
- inner: IAsn1Object;
- asn1Set: IAsn1Set;
- asn1Sequence: IAsn1Sequence;
- v: IAsn1EncodableVector;
- ae: IAsn1Encodable;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- inner := obj.GetObject();
- if (explicitly) then
- begin
- if (not(obj.isExplicit())) then
- raise EArgumentCryptoLibException.CreateRes(@SInvalidObject);
- result := inner as IAsn1Set;
- Exit;
- end;
- //
- // constructed object which appears to be explicitly tagged
- // when it should be implicit means we have to add the
- // surrounding sequence.
- //
- if (obj.isExplicit()) then
- begin
- result := TDerSet.Create(inner);
- Exit;
- end;
- if (Supports(inner, IAsn1Set, asn1Set)) then
- begin
- result := asn1Set;
- Exit;
- end;
- //
- // in this case the parser returns a sequence, convert it
- // into a set.
- //
- if (Supports(inner, IAsn1Sequence, asn1Sequence)) then
- begin
- v := TAsn1EncodableVector.Create();
- LListAsn1Encodable := asn1Sequence.GetEnumerable;
- for ae in LListAsn1Encodable do
- begin
- v.Add(ae);
- end;
- // TODO Should be able to construct set directly from sequence?
- result := TDerSet.Create(v, False);
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SUnknownObject,
- [(obj as TAsn1TaggedObject).ClassName]);
- end;
- class function TAsn1Set.GetInstance(const obj: TObject): IAsn1Set;
- var
- primitive: IAsn1Object;
- asn1Set: IAsn1Set;
- res: IAsn1SetParser;
- begin
- if ((obj = Nil) or (obj is TAsn1Set)) then
- begin
- result := obj as TAsn1Set;
- Exit;
- end;
- if (Supports(obj, IAsn1SetParser, res)) then
- begin
- result := TAsn1Set.GetInstance(res.ToAsn1Object() as TAsn1Object);
- Exit;
- end;
- if (obj is TAsn1Encodable) then
- begin
- primitive := (obj as TAsn1Encodable).ToAsn1Object();
- if (Supports(primitive, IAsn1Set, asn1Set)) then
- begin
- result := asn1Set;
- Exit;
- end;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SUnknownObject,
- [obj.ClassName]);
- end;
- function TAsn1Set.GetParser: IAsn1SetParser;
- begin
- result := TAsn1SetParserImpl.Create(Self as IAsn1Set);
- end;
- function TAsn1Set.GetSelf(Index: Int32): IAsn1Encodable;
- begin
- result := FElements[Index];
- end;
- class function TAsn1Set.LessThanOrEqual(const a,
- b: TCryptoLibByteArray): Boolean;
- var
- last, I, a0, b0: Int32;
- begin
- {$IFDEF DEBUG}
- System.Assert((System.length(a) >= 2) and (System.length(b) >= 2));
- {$ENDIF DEBUG}
- (*
- * NOTE: Set elements in DER encodings are ordered first according to their tags (class and
- * number); the CONSTRUCTED bit is not part of the tag.
- *
- * For SET-OF, this is unimportant. All elements have the same tag and DER requires them to
- * either all be in constructed form or all in primitive form, according to that tag. The
- * elements are effectively ordered according to their content octets.
- *
- * For SET, the elements will have distinct tags, and each will be in constructed or
- * primitive form accordingly. Failing to ignore the CONSTRUCTED bit could therefore lead to
- * ordering inversions.
- *)
- a0 := a[0] and (not TAsn1Tags.Constructed);
- b0 := b[0] and (not TAsn1Tags.Constructed);
- if (a0 <> b0) then
- begin
- result := a0 < b0;
- Exit;
- end;
- last := Math.Min(System.length(a), System.length(b)) - 1;
- I := 1;
- while I < last do
- begin
- if (a[I] <> b[I]) then
- begin
- result := (a[I]) < (b[I]);
- Exit;
- end;
- System.Inc(I);
- end;
- result := (a[last]) <= (b[last]);
- end;
- procedure TAsn1Set.Sort;
- var
- count, I, j: Int32;
- eh, ei, et, e2, e1: IAsn1Encodable;
- bh, bi, bt, b2, b1: TCryptoLibByteArray;
- begin
- count := System.length(FElements);
- if (count < 2) then
- begin
- Exit;
- end;
- eh := FElements[0];
- ei := FElements[1];
- bh := GetDerEncoded(eh);
- bi := GetDerEncoded(ei);
- if (LessThanOrEqual(bi, bh)) then
- begin
- et := ei;
- ei := eh;
- eh := et;
- bt := bi;
- bi := bh;
- bh := bt;
- end;
- for I := 2 to System.Pred(count) do
- begin
- e2 := FElements[I];
- b2 := GetDerEncoded(e2);
- if (LessThanOrEqual(bi, b2)) then
- begin
- FElements[I - 2] := eh;
- eh := ei;
- bh := bi;
- ei := e2;
- bi := b2;
- continue;
- end;
- if (LessThanOrEqual(bh, b2)) then
- begin
- FElements[I - 2] := eh;
- eh := e2;
- bh := b2;
- continue;
- end;
- j := I - 1;
- System.Dec(j);
- while (j > 0) do
- begin
- e1 := FElements[j - 1];
- b1 := GetDerEncoded(e1);
- if (LessThanOrEqual(b1, b2)) then
- begin
- break;
- end;
- FElements[j] := e1;
- System.Dec(j);
- end;
- FElements[j] := e2;
- end;
- FElements[count - 2] := eh;
- FElements[count - 1] := ei;
- end;
- function TAsn1Set.ToArray: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- result := TAsn1EncodableVector.CloneElements(FElements);
- end;
- function TAsn1Set.ToString: String;
- begin
- result := TCollectionUtilities.ToStructuredString(FElements);
- end;
- { TAsn1Set.TAsn1SetParserImpl }
- constructor TAsn1Set.TAsn1SetParserImpl.Create(const outer: IAsn1Set);
- begin
- Inherited Create();
- Fouter := outer;
- Fmax := outer.count;
- end;
- function TAsn1Set.TAsn1SetParserImpl.ReadObject: IAsn1Convertible;
- var
- obj: IAsn1Encodable;
- Sequence: IAsn1Sequence;
- asn1Set: IAsn1Set;
- begin
- if (Findex = Fmax) then
- begin
- result := Nil;
- Exit;
- end;
- obj := Fouter[Findex];
- System.Inc(Findex);
- if (Supports(obj, IAsn1Sequence, Sequence)) then
- begin
- result := Sequence.parser;
- Exit;
- end;
- if (Supports(obj, IAsn1Set, asn1Set)) then
- begin
- result := asn1Set.parser;
- Exit;
- end;
- // NB: Asn1OctetString implements Asn1OctetStringParser directly
- // if (obj is Asn1OctetString)
- // return ((Asn1OctetString)obj).Parser;
- result := obj;
- end;
- function TAsn1Set.TAsn1SetParserImpl.ToAsn1Object: IAsn1Object;
- begin
- result := Fouter;
- end;
- { TDerSet }
- class function TDerSet.GetEmpty: IDerSet;
- begin
- result := TDerSet.Create();
- end;
- constructor TDerSet.Create(const elements: array of IAsn1Encodable);
- begin
- Inherited Create(elements);
- Sort();
- end;
- constructor TDerSet.Create;
- begin
- Inherited Create();
- end;
- constructor TDerSet.Create(const element: IAsn1Encodable);
- begin
- Inherited Create(element);
- end;
- constructor TDerSet.Create(const elementVector: IAsn1EncodableVector);
- begin
- Create(elementVector, True);
- end;
- constructor TDerSet.Create(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean);
- begin
- Inherited Create(elementVector);
- if (needsSorting) then
- begin
- Sort();
- end;
- end;
- destructor TDerSet.Destroy;
- begin
- inherited Destroy;
- end;
- procedure TDerSet.Encode(const derOut: TStream);
- var
- bOut: TMemoryStream;
- dOut: TDerOutputStream;
- obj: IAsn1Encodable;
- bytes: TCryptoLibByteArray;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- // TODO Intermediate buffer could be avoided if we could calculate expected length
- bOut := TMemoryStream.Create();
- dOut := TDerOutputStream.Create(bOut);
- try
- LListAsn1Encodable := Self.GetEnumerable;
- for obj in LListAsn1Encodable do
- begin
- dOut.WriteObject(obj);
- end;
- System.SetLength(bytes, bOut.Size);
- bOut.Position := 0;
- bOut.Read(bytes[0], bOut.Size);
- finally
- bOut.Free;
- dOut.Free;
- end;
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.&Set or
- TAsn1Tags.Constructed, bytes);
- end;
- class function TDerSet.FromVector(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean): IDerSet;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TDerSet.Create(elementVector, needsSorting);
- end;
- end;
- class function TDerSet.FromVector(const elementVector
- : IAsn1EncodableVector): IDerSet;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TDerSet.Create(elementVector);
- end;
- end;
- { TAsn1StreamParser }
- procedure TAsn1StreamParser.Set00Check(enabled: Boolean);
- var
- indefiniteLengthInputStream: TIndefiniteLengthInputStream;
- begin
- if (F_in is TIndefiniteLengthInputStream) then
- begin
- indefiniteLengthInputStream := F_in as TIndefiniteLengthInputStream;
- indefiniteLengthInputStream.SetEofOn00(enabled);
- end;
- end;
- constructor TAsn1StreamParser.Create(const inStream: TStream);
- begin
- Create(inStream, TAsn1InputStream.FindLimit(inStream));
- end;
- constructor TAsn1StreamParser.Create(const inStream: TStream; limit: Int32);
- begin
- Inherited Create();
- F_in := inStream;
- F_limit := limit;
- System.SetLength(FtmpBuffers, 16);
- end;
- constructor TAsn1StreamParser.Create(const encoding: TCryptoLibByteArray);
- begin
- // used TBytesStream here for one pass creation and population with byte array :)
- Create(TBytesStream.Create(encoding), System.length(encoding));
- end;
- destructor TAsn1StreamParser.Destroy;
- begin
- F_in.Free;
- inherited Destroy;
- end;
- function TAsn1StreamParser.ReadVector: IAsn1EncodableVector;
- var
- obj: IAsn1Convertible;
- begin
- obj := ReadObject();
- if obj = Nil then
- begin
- result := TAsn1EncodableVector.Create(0);
- Exit;
- end;
- result := TAsn1EncodableVector.Create();
- repeat
- result.Add([obj.ToAsn1Object()]);
- obj := ReadObject();
- until not(obj <> Nil);
- end;
- function TAsn1StreamParser.ReadImplicit(Constructed: Boolean; tag: Int32)
- : IAsn1Convertible;
- begin
- if (F_in is TIndefiniteLengthInputStream) then
- begin
- if (not Constructed) then
- begin
- raise EIOCryptoLibException.CreateRes(@SIndefiniteLength);
- end;
- result := ReadIndef(tag);
- Exit;
- end;
- if (Constructed) then
- begin
- case tag of
- TAsn1Tags.&Set:
- begin
- result := TDerSetParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.Sequence:
- begin
- result := TDerSequenceParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.OctetString:
- begin
- result := TBerOctetStringParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- end;
- end
- else
- begin
- case tag of
- TAsn1Tags.&Set:
- begin
- raise EAsn1CryptoLibException.CreateRes(@SUnConstructedEncoding);
- end;
- TAsn1Tags.Sequence:
- begin
- raise EAsn1CryptoLibException.CreateRes(@SUnConstructedEncoding2);
- end;
- TAsn1Tags.OctetString:
- begin
- result := TDerOctetStringParser.Create
- (F_in as TDefiniteLengthInputStream);
- Exit;
- end;
- end;
- end;
- raise EAsn1CryptoLibException.CreateRes(@SImplicitTagging);
- end;
- function TAsn1StreamParser.ReadIndef(tagValue: Int32): IAsn1Convertible;
- begin
- // Note: INDEF => CONSTRUCTED
- // TODO There are other tags that may be constructed (e.g. BIT_STRING)
- case tagValue of
- TAsn1Tags.External:
- begin
- result := TDerExternalParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.OctetString:
- begin
- result := TBerOctetStringParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.Sequence:
- begin
- result := TBerSequenceParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.&Set:
- begin
- result := TBerSetParser.Create(Self as IAsn1StreamParser);
- Exit;
- end;
- else
- begin
- raise EAsn1CryptoLibException.CreateResFmt(@SUnknownObjectBER,
- [tagValue]);
- end;
- end;
- end;
- function TAsn1StreamParser.ReadObject: IAsn1Convertible;
- var
- tag, tagNo, &length: Int32;
- IsConstructed: Boolean;
- indIn: TIndefiniteLengthInputStream;
- sp: IAsn1StreamParser;
- defIn: TDefiniteLengthInputStream;
- begin
- tag := TStreamSorter.ReadByte(F_in);
- if (tag = -1) then
- begin
- result := Nil;
- Exit;
- end;
- // turn off looking for "00" while we resolve the tag
- Set00Check(False);
- //
- // calculate tag number
- //
- tagNo := TAsn1InputStream.ReadTagNumber(F_in, tag);
- IsConstructed := (tag and TAsn1Tags.Constructed) <> 0;
- //
- // calculate length
- //
- length := TAsn1InputStream.ReadLength(F_in, F_limit);
- if (length < 0) then // indefinite length method
- begin
- if (not IsConstructed) then
- begin
- raise EIOCryptoLibException.CreateRes(@SIndefiniteLength);
- end;
- indIn := TIndefiniteLengthInputStream.Create(F_in, F_limit);
- sp := TAsn1StreamParser.Create(indIn, F_limit);
- if ((tag and TAsn1Tags.Application) <> 0) then
- begin
- result := TBerApplicationSpecificParser.Create(tagNo, sp);
- Exit;
- end;
- if ((tag and TAsn1Tags.Tagged) <> 0) then
- begin
- result := TBerTaggedObjectParser.Create(True, tagNo, sp);
- Exit;
- end;
- result := sp.ReadIndef(tagNo);
- Exit;
- end;
- defIn := TDefiniteLengthInputStream.Create(F_in, length);
- if ((tag and TAsn1Tags.Application) <> 0) then
- begin
- try
- result := TDerApplicationSpecific.Create(IsConstructed, tagNo,
- defIn.ToArray());
- Exit;
- finally
- defIn.Free;
- end;
- end;
- if ((tag and TAsn1Tags.Tagged) <> 0) then
- begin
- result := TBerTaggedObjectParser.Create(IsConstructed, tagNo,
- TAsn1StreamParser.Create(defIn) as IAsn1StreamParser);
- Exit;
- end;
- if (IsConstructed) then
- begin
- // TODO There are other tags that may be constructed (e.g. BitString)
- case tagNo of
- TAsn1Tags.OctetString:
- begin
- //
- // yes, people actually do this...
- //
- result := TBerOctetStringParser.Create(TAsn1StreamParser.Create(defIn)
- as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.Sequence:
- begin
- result := TDerSequenceParser.Create(TAsn1StreamParser.Create(defIn)
- as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.&Set:
- begin
- result := TDerSetParser.Create(TAsn1StreamParser.Create(defIn)
- as IAsn1StreamParser);
- Exit;
- end;
- TAsn1Tags.External:
- begin
- result := TDerExternalParser.Create(TAsn1StreamParser.Create(defIn)
- as IAsn1StreamParser);
- Exit;
- end;
- else
- begin
- defIn.Free; // free the stream incase an unsupported tag is encountered.
- raise EIOCryptoLibException.CreateResFmt(@SUnknownTag, [tagNo]);
- end;
- end;
- end;
- // Some primitive encodings can be handled by parsers too...
- case tagNo of
- TAsn1Tags.OctetString:
- begin
- result := TDerOctetStringParser.Create(defIn);
- Exit;
- end;
- end;
- try
- try
- result := TAsn1InputStream.CreatePrimitiveDerObject(tagNo, defIn,
- FtmpBuffers);
- Exit;
- except
- on e: EArgumentCryptoLibException do
- begin
- raise EAsn1CryptoLibException.CreateResFmt(@SCorruptedStream,
- [e.Message]);
- end;
- end;
- finally
- defIn.Free;
- end;
- end;
- function TAsn1StreamParser.ReadTaggedObject(Constructed: Boolean; tag: Int32)
- : IAsn1Object;
- var
- defIn: TDefiniteLengthInputStream;
- v: IAsn1EncodableVector;
- begin
- if (not Constructed) then
- begin
- // Note: !CONSTRUCTED => IMPLICIT
- defIn := F_in as TDefiniteLengthInputStream;
- result := TDerTaggedObject.Create(False, tag,
- TDerOctetString.Create(defIn.ToArray()));
- Exit;
- end;
- v := ReadVector();
- if (F_in is TIndefiniteLengthInputStream) then
- begin
- if v.count = 1 then
- begin
- result := TBerTaggedObject.Create(True, tag, v[0]);
- Exit;
- end
- else
- begin
- result := TBerTaggedObject.Create(False, tag, TBerSequence.FromVector(v));
- Exit;
- end;
- end;
- if v.count = 1 then
- begin
- result := TDerTaggedObject.Create(True, tag, v[0]);
- Exit;
- end
- else
- begin
- result := TDerTaggedObject.Create(False, tag, TDerSequence.FromVector(v));
- Exit;
- end;
- end;
- { TDerSetParser }
- constructor TDerSetParser.Create(const parser: IAsn1StreamParser);
- begin
- F_parser := parser;
- end;
- function TDerSetParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TDerSetParser.ToAsn1Object: IAsn1Object;
- begin
- result := TDerSet.Create(F_parser.ReadVector(), False);
- end;
- { TDerSequenceParser }
- constructor TDerSequenceParser.Create(const parser: IAsn1StreamParser);
- begin
- F_parser := parser;
- end;
- function TDerSequenceParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TDerSequenceParser.ToAsn1Object: IAsn1Object;
- begin
- result := TDerSequence.Create(F_parser.ReadVector());
- end;
- { TDerApplicationSpecific }
- function TDerApplicationSpecific.GetApplicationTag: Int32;
- begin
- result := Ftag;
- end;
- function TDerApplicationSpecific.GetContents: TCryptoLibByteArray;
- begin
- result := Foctets;
- end;
- function TDerApplicationSpecific.IsConstructed: Boolean;
- begin
- result := FisConstructed;
- end;
- function TDerApplicationSpecific.GetLengthOfHeader
- (const data: TCryptoLibByteArray): Int32;
- var
- &length, Size: Int32;
- begin
- length := data[1]; // TODO: assumes 1 byte tag
- if (length = $80) then
- begin
- result := 2; // indefinite-length encoding
- Exit;
- end;
- if (length > 127) then
- begin
- Size := length and $7F;
- // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
- if (Size > 4) then
- begin
- raise EInvalidOperationCryptoLibException.CreateResFmt
- (@SInvalidDerLength, [Size]);
- end;
- result := Size + 2;
- Exit;
- end;
- result := 2;
- end;
- constructor TDerApplicationSpecific.Create(tag: Int32;
- const obj: IAsn1Encodable);
- begin
- Create(True, tag, obj);
- end;
- constructor TDerApplicationSpecific.Create(tag: Int32;
- const octets: TCryptoLibByteArray);
- begin
- Create(False, tag, octets);
- end;
- constructor TDerApplicationSpecific.Create(IsConstructed: Boolean; tag: Int32;
- const octets: TCryptoLibByteArray);
- begin
- Inherited Create();
- FisConstructed := IsConstructed;
- Ftag := tag;
- Foctets := octets;
- end;
- function TDerApplicationSpecific.Asn1Equals(const asn1Object
- : IAsn1Object): Boolean;
- var
- other: IDerApplicationSpecific;
- begin
- if (not Supports(asn1Object, IDerApplicationSpecific, other)) then
- begin
- result := False;
- Exit;
- end;
- result := (IsConstructed = other.IsConstructed) and
- (ApplicationTag = other.ApplicationTag) and
- TArrayUtils.AreEqual(GetContents, other.GetContents);
- end;
- function TDerApplicationSpecific.Asn1GetHashCode: Int32;
- var
- HashCode: Int32;
- begin
- case IsConstructed of
- True:
- HashCode := 1;
- False:
- HashCode := 0;
- end;
- result := HashCode xor Ftag xor TArrayUtils.GetArrayHashCode(Foctets);
- end;
- constructor TDerApplicationSpecific.Create(tagNo: Int32;
- const vec: IAsn1EncodableVector);
- var
- bOut: TMemoryStream;
- bs: TCryptoLibByteArray;
- I: Int32;
- val: IAsn1Encodable;
- begin
- Inherited Create();
- Ftag := tagNo;
- FisConstructed := True;
- bOut := TMemoryStream.Create();
- try
- I := 0;
- while I <> vec.count do
- begin
- try
- val := vec[I];
- bs := val.GetDerEncoded();
- bOut.Write(bs[0], System.length(bs));
- except
- on e: EIOCryptoLibException do
- begin
- raise EInvalidOperationCryptoLibException.CreateResFmt
- (@SMalformedObject, [e.Message]);
- end;
- end;
- System.Inc(I);
- end;
- System.SetLength(Foctets, bOut.Size);
- bOut.Position := 0;
- bOut.Read(Foctets[0], bOut.Size);
- finally
- bOut.Free;
- end;
- end;
- procedure TDerApplicationSpecific.Encode(const derOut: TStream);
- var
- classBits: Int32;
- begin
- classBits := TAsn1Tags.Application;
- if (IsConstructed) then
- begin
- classBits := classBits or TAsn1Tags.Constructed;
- end;
- (derOut as TDerOutputStream).WriteEncoded(classBits, Ftag, Foctets);
- end;
- constructor TDerApplicationSpecific.Create(isExplicit: Boolean; tag: Int32;
- const obj: IAsn1Encodable);
- var
- asn1Obj: IAsn1Object;
- data, tmp: TCryptoLibByteArray;
- lenBytes: Int32;
- begin
- Inherited Create();
- asn1Obj := obj.ToAsn1Object();
- data := asn1Obj.GetDerEncoded();
- FisConstructed := TAsn1TaggedObject.IsConstructed(isExplicit, asn1Obj);
- Ftag := tag;
- if (isExplicit) then
- begin
- Foctets := data;
- end
- else
- begin
- lenBytes := GetLengthOfHeader(data);
- System.SetLength(tmp, System.length(data) - lenBytes);
- System.Move(data[lenBytes], tmp[0], System.length(tmp) *
- System.SizeOf(Byte));
- Foctets := tmp;
- end;
- end;
- function TDerApplicationSpecific.GetObject: IAsn1Object;
- begin
- result := FromByteArray(GetContents());
- end;
- function TDerApplicationSpecific.GetObject(derTagNo: Int32): IAsn1Object;
- var
- orig, tmp: TCryptoLibByteArray;
- begin
- if (derTagNo >= $1F) then
- begin
- raise EIOCryptoLibException.CreateRes(@SUnSupportedTag);
- end;
- orig := GetEncoded();
- tmp := ReplaceTagNumber(derTagNo, orig);
- if ((orig[0] and TAsn1Tags.Constructed) <> 0) then
- begin
- tmp[0] := tmp[0] or TAsn1Tags.Constructed;
- end;
- result := FromByteArray(tmp);
- end;
- class function TDerApplicationSpecific.ReplaceTagNumber(newTag: Int32;
- const input: TCryptoLibByteArray): TCryptoLibByteArray;
- var
- tagNo, Index, b, Remaining: Int32;
- tmp: TCryptoLibByteArray;
- begin
- tagNo := input[0] and $1F;
- index := 1;
- //
- // with tagged object tag number is bottom 5 bits, or stored at the start of the content
- //
- if (tagNo = $1F) then
- begin
- b := input[index];
- System.Inc(index);
- // X.690-0207 8.1.2.4.2
- // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
- if ((b and $7F) = 0) then // Note: -1 will pass
- begin
- raise EIOCryptoLibException.CreateRes(@SCorruptedStreamInvalidTag);
- end;
- while ((b and $80) <> 0) do
- begin
- b := input[index];
- System.Inc(index);
- end;
- end;
- Remaining := System.length(input) - index;
- System.SetLength(tmp, 1 + Remaining);
- tmp[0] := Byte(newTag);
- System.Move(input[index], tmp[1], Remaining * System.SizeOf(Byte));
- result := tmp;
- end;
- { TBerApplicationSpecific }
- constructor TBerApplicationSpecific.Create(tagNo: Int32;
- const vec: IAsn1EncodableVector);
- begin
- inherited Create(tagNo, vec);
- end;
- { TBerOctetStringParser }
- constructor TBerOctetStringParser.Create(const parser: IAsn1StreamParser);
- begin
- Inherited Create();
- F_parser := parser;
- end;
- function TBerOctetStringParser.GetOctetStream: TStream;
- begin
- result := TConstructedOctetStream.Create(F_parser);
- end;
- function TBerOctetStringParser.ToAsn1Object: IAsn1Object;
- var
- LStream: TStream;
- begin
- try
- LStream := GetOctetStream();
- try
- result := TBerOctetString.Create(TStreamUtils.ReadAll(LStream));
- finally
- LStream.Free;
- end;
- except
- on e: EIOCryptoLibException do
- begin
- raise EAsn1ParsingCryptoLibException.CreateResFmt(@SConvertError,
- [e.Message]);
- end;
- end;
- end;
- { TBerApplicationSpecificParser }
- constructor TBerApplicationSpecificParser.Create(tag: Int32;
- const parser: IAsn1StreamParser);
- begin
- F_tag := tag;
- F_parser := parser;
- end;
- function TBerApplicationSpecificParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TBerApplicationSpecificParser.ToAsn1Object: IAsn1Object;
- begin
- result := TBerApplicationSpecific.Create(F_tag, F_parser.ReadVector());
- end;
- { TDerStringBase }
- function TDerStringBase.Asn1GetHashCode: Int32;
- begin
- result := TStringUtils.GetStringHashCode(GetString());
- end;
- constructor TDerStringBase.Create;
- begin
- Inherited Create();
- end;
- function TDerStringBase.ToString: String;
- begin
- result := GetString();
- end;
- { TDerBitString }
- class function TDerBitString.GetInstance(const obj: TCryptoLibByteArray)
- : IDerBitString;
- begin
- try
- result := FromByteArray(obj) as IDerBitString;
- except
- on e: Exception do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SEncodingError,
- [e.Message]);
- end;
- end;
- end;
- function TDerBitString.GetmData: TCryptoLibByteArray;
- begin
- result := FmData;
- end;
- function TDerBitString.GetmPadBits: Int32;
- begin
- result := FmPadBits;
- end;
- function TDerBitString.GetOctets: TCryptoLibByteArray;
- begin
- if (mPadBits <> 0) then
- begin
- raise EInvalidOperationCryptoLibException.CreateRes(@SUnalignedData);
- end;
- result := System.Copy(mData);
- end;
- function TDerBitString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerBitString;
- begin
- if (not Supports(asn1Object, IDerBitString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := (mPadBits = other.mPadBits) and
- (TArrayUtils.AreEqual(mData, other.mData));
- end;
- constructor TDerBitString.Create(const data: TCryptoLibByteArray;
- padBits: Int32);
- begin
- Inherited Create();
- if (data = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SDataNil);
- end;
- if ((padBits < 0) or (padBits > 7)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInvalidRange);
- end;
- if ((System.length(data) = 0) and (padBits <> 0)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SPadBitError);
- end;
- FmData := System.Copy(data);
- FmPadBits := padBits;
- end;
- constructor TDerBitString.Create(const data: TCryptoLibByteArray);
- begin
- Create(data, 0);
- end;
- constructor TDerBitString.Create(namedBits: Int32);
- var
- bits, bytes, I, padBits: Int32;
- data: TCryptoLibByteArray;
- begin
- Inherited Create();
- if (namedBits = 0) then
- begin
- System.SetLength(FmData, 0);
- FmPadBits := 0;
- Exit;
- end;
- bits := TBigInteger.BitLen(namedBits);
- bytes := (bits + 7) div 8;
- {$IFDEF DEBUG}
- System.Assert((0 < bytes) and (bytes <= 4));
- {$ENDIF DEBUG}
- System.SetLength(data, bytes);
- System.Dec(bytes);
- for I := 0 to System.Pred(bytes) do
- begin
- data[I] := Byte(namedBits);
- namedBits := TBits.Asr32(namedBits, 8);
- end;
- {$IFDEF DEBUG}
- System.Assert((namedBits and $FF) <> 0);
- {$ENDIF DEBUG}
- data[bytes] := Byte(namedBits);
- padBits := 0;
- while ((namedBits and (1 shl padBits)) = 0) do
- begin
- System.Inc(padBits);
- end;
- {$IFDEF DEBUG}
- System.Assert(padBits < 8);
- {$ENDIF DEBUG}
- FmData := data;
- FmPadBits := padBits;
- end;
- procedure TDerBitString.Encode(const derOut: TStream);
- var
- last, mask, unusedBits: Int32;
- contents: TCryptoLibByteArray;
- begin
- if (mPadBits > 0) then
- begin
- last := mData[System.length(mData) - 1];
- mask := (1 shl mPadBits) - 1;
- unusedBits := last and mask;
- if (unusedBits <> 0) then
- begin
- contents := TArrayUtils.Prepend(mData, Byte(mPadBits));
- // /*
- // * X.690-0207 11.2.1: Each unused bit in the final octet of the encoding of a bit string value shall be set to zero.
- // */
- contents[System.length(contents) - 1] := Byte(last xor unusedBits);
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.BitString, contents);
- Exit;
- end;
- end;
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.BitString,
- Byte(mPadBits), mData);
- end;
- class function TDerBitString.FromAsn1Octets(const octets: TCryptoLibByteArray)
- : IDerBitString;
- var
- padBits, last, mask: Int32;
- data: TCryptoLibByteArray;
- begin
- if (System.length(octets) < 1) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@STruncatedBitString);
- end;
- padBits := octets[0];
- data := TArrayUtils.CopyOfRange(octets, 1, System.length(octets));
- if ((padBits > 0) and (padBits < 8) and (System.length(data) > 0)) then
- begin
- last := data[System.length(data) - 1];
- mask := (1 shl padBits) - 1;
- if ((last and mask) <> 0) then
- begin
- result := TBerBitString.Create(data, padBits);
- Exit;
- end;
- end;
- result := TDerBitString.Create(data, padBits);
- end;
- function TDerBitString.GetBytes: TCryptoLibByteArray;
- begin
- result := System.Copy(mData);
- // DER requires pad bits be zero
- if (mPadBits > 0) then
- begin
- result[System.length(result) - 1] := result[System.length(result) - 1] and
- Byte($FF shl mPadBits);
- end;
- end;
- class function TDerBitString.GetInstance(const obj: TObject): IDerBitString;
- begin
- if ((obj = Nil) or (obj is TDerBitString)) then
- begin
- result := obj as TDerBitString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerBitString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBitString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerBitString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := FromAsn1Octets((o as IAsn1OctetString).GetOctets());
- end;
- function TDerBitString.GetInt32Value: Int32;
- var
- Value, &length, I, mask: Int32;
- begin
- Value := 0;
- length := Min(4, System.length(mData));
- for I := 0 to System.Pred(length) do
- begin
- Value := Value or (Int32(mData[I]) shl (8 * I));
- end;
- if ((mPadBits > 0) and (length = System.length(mData))) then
- begin
- mask := (1 shl mPadBits) - 1;
- Value := Value and (not(mask shl (8 * (length - 1))));
- end;
- result := Value;
- end;
- function TDerBitString.GetString: String;
- var
- buffer: TStringList;
- I: Int32;
- Str: TCryptoLibByteArray;
- ubyte: UInt32;
- begin
- buffer := TStringList.Create();
- buffer.LineBreak := '';
- Str := GetDerEncoded();
- buffer.Add('#');
- I := 0;
- try
- while I <> System.length(Str) do
- begin
- ubyte := Str[I];
- buffer.Add(FTable[(ubyte shr 4) and $F]);
- buffer.Add(FTable[Str[I] and $F]);
- System.Inc(I);
- end;
- result := buffer.Text;
- finally
- buffer.Free;
- end;
- end;
- function TDerBitString.Asn1GetHashCode: Int32;
- begin
- result := mPadBits xor TArrayUtils.GetArrayHashCode(mData);
- end;
- constructor TDerBitString.Create(const obj: IAsn1Encodable);
- begin
- Create(obj.GetDerEncoded());
- end;
- { TBerBitString }
- constructor TBerBitString.Create(const data: TCryptoLibByteArray);
- begin
- Inherited Create(data);
- end;
- constructor TBerBitString.Create(const data: TCryptoLibByteArray;
- padBits: Int32);
- begin
- Inherited Create(data, padBits);
- end;
- constructor TBerBitString.Create(const obj: IAsn1Encodable);
- begin
- Inherited Create(obj);
- end;
- constructor TBerBitString.Create(namedBits: Int32);
- begin
- Inherited Create(namedBits);
- end;
- procedure TBerBitString.Encode(const derOut: TStream);
- begin
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.BitString,
- Byte(mPadBits), mData);
- end
- else
- begin
- Inherited Encode(derOut);
- end;
- end;
- { TBerGenerator }
- constructor TBerGenerator.Create(outStream: TStream);
- begin
- Inherited Create(outStream);
- end;
- procedure TBerGenerator.AddObject(const obj: IAsn1Encodable);
- var
- temp: TBerOutputStream;
- begin
- temp := TBerOutputStream.Create(&Out);
- try
- temp.WriteObject(obj);
- finally
- temp.Free;
- end;
- end;
- procedure TBerGenerator.Close;
- begin
- WriteBerEnd();
- end;
- constructor TBerGenerator.Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean);
- begin
- Inherited Create(outStream);
- F_tagged := True;
- F_isExplicit := isExplicit;
- F_tagNo := tagNo;
- end;
- function TBerGenerator.GetRawOutputStream: TStream;
- begin
- result := &Out;
- end;
- procedure TBerGenerator.WriteBerBody(contentStream: TStream);
- begin
- TStreamUtils.PipeAll(contentStream, &Out);
- end;
- procedure TBerGenerator.WriteBerEnd;
- begin
- &Out.WriteByte($00);
- &Out.WriteByte($00);
- if (F_tagged and F_isExplicit) then // write extra end for tag header
- begin
- &Out.WriteByte($00);
- &Out.WriteByte($00);
- end;
- end;
- procedure TBerGenerator.WriteBerHeader(tag: Int32);
- var
- tagNum: Int32;
- begin
- if (F_tagged) then
- begin
- tagNum := F_tagNo or TAsn1Tags.Tagged;
- if (F_isExplicit) then
- begin
- WriteHdr(tagNum or TAsn1Tags.Constructed);
- WriteHdr(tag);
- end
- else
- begin
- if ((tag and TAsn1Tags.Constructed) <> 0) then
- begin
- WriteHdr(tagNum or TAsn1Tags.Constructed);
- end
- else
- begin
- WriteHdr(tagNum);
- end;
- end
- end
- else
- begin
- WriteHdr(tag);
- end;
- end;
- procedure TBerGenerator.WriteHdr(tag: Int32);
- begin
- &Out.WriteByte(Byte(tag));
- &Out.WriteByte($80);
- end;
- { TBerNull }
- constructor TBerNull.Create(dummy: Int32);
- begin
- Inherited Create(dummy);
- end;
- procedure TBerNull.Encode(const derOut: TStream);
- begin
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream).WriteByte(TAsn1Tags.Null);
- end
- else
- begin
- Inherited Encode(derOut);
- end;
- end;
- class function TBerNull.GetInstance: IBerNull;
- begin
- result := TBerNull.Create(0);
- end;
- { TBerSequenceGenerator }
- constructor TBerSequenceGenerator.Create(outStream: TStream);
- begin
- Inherited Create(outStream);
- WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
- end;
- constructor TBerSequenceGenerator.Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean);
- begin
- Inherited Create(outStream, tagNo, isExplicit);
- WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
- end;
- { TBerSequenceParser }
- constructor TBerSequenceParser.Create(const parser: IAsn1StreamParser);
- begin
- F_parser := parser;
- end;
- function TBerSequenceParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TBerSequenceParser.ToAsn1Object: IAsn1Object;
- begin
- result := TBerSequence.Create(F_parser.ReadVector());
- end;
- { TBerSet }
- class function TBerSet.GetEmpty: IBerSet;
- begin
- result := TBerSet.Create();
- end;
- constructor TBerSet.Create;
- begin
- Inherited Create();
- end;
- constructor TBerSet.Create(const v: IAsn1EncodableVector;
- needsSorting: Boolean);
- begin
- Inherited Create(v, needsSorting);
- end;
- destructor TBerSet.Destroy;
- begin
- inherited Destroy;
- end;
- constructor TBerSet.Create(const element: IAsn1Encodable);
- begin
- Inherited Create(element);
- end;
- constructor TBerSet.Create(const elementVector: IAsn1EncodableVector);
- begin
- Inherited Create(elementVector, False);
- end;
- procedure TBerSet.Encode(const derOut: TStream);
- var
- o: IAsn1Encodable;
- LListAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- begin
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream).WriteByte(TAsn1Tags.&Set or
- TAsn1Tags.Constructed);
- (derOut as TDerOutputStream).WriteByte($80);
- LListAsn1Encodable := Self.GetEnumerable;
- for o in LListAsn1Encodable do
- begin
- (derOut as TDerOutputStream).WriteObject(o);
- end;
- (derOut as TDerOutputStream).WriteByte($00);
- (derOut as TDerOutputStream).WriteByte($00);
- end
- else
- begin
- (Inherited Encode(derOut));
- end;
- end;
- class function TBerSet.FromVector(const elementVector: IAsn1EncodableVector;
- needsSorting: Boolean): IBerSet;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TBerSet.Create(elementVector, needsSorting);
- end;
- end;
- class function TBerSet.FromVector(const elementVector
- : IAsn1EncodableVector): IBerSet;
- begin
- if elementVector.count < 1 then
- begin
- result := Empty;
- end
- else
- begin
- result := TBerSet.Create(elementVector);
- end;
- end;
- { TBerSetParser }
- constructor TBerSetParser.Create(const parser: IAsn1StreamParser);
- begin
- F_parser := parser;
- end;
- function TBerSetParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TBerSetParser.ToAsn1Object: IAsn1Object;
- begin
- result := TBerSet.Create(F_parser.ReadVector(), False);
- end;
- { TDerTaggedObject }
- constructor TDerTaggedObject.Create(tagNo: Int32; const obj: IAsn1Encodable);
- begin
- Inherited Create(tagNo, obj);
- end;
- constructor TDerTaggedObject.Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable);
- begin
- Inherited Create(explicitly, tagNo, obj)
- end;
- constructor TDerTaggedObject.Create(tagNo: Int32);
- begin
- Inherited Create(False, tagNo, TDerSequence.Empty)
- end;
- procedure TDerTaggedObject.Encode(const derOut: TStream);
- var
- bytes: TCryptoLibByteArray;
- flags: Int32;
- begin
- if (not IsEmpty()) then
- begin
- bytes := obj.GetDerEncoded();
- if (explicitly) then
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Constructed or
- TAsn1Tags.Tagged, tagNo, bytes);
- end
- else
- begin
- //
- // need to mark constructed types... (preserve Constructed tag)
- //
- flags := (bytes[0] and TAsn1Tags.Constructed) or TAsn1Tags.Tagged;
- (derOut as TDerOutputStream).WriteTag(flags, tagNo);
- derOut.Write(bytes[1], System.length(bytes) - 1);
- end
- end
- else
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Constructed or
- TAsn1Tags.Tagged, tagNo, Nil);
- end;
- end;
- { TBerTaggedObject }
- constructor TBerTaggedObject.Create(tagNo: Int32; const obj: IAsn1Encodable);
- begin
- Inherited Create(tagNo, obj);
- end;
- constructor TBerTaggedObject.Create(explicitly: Boolean; tagNo: Int32;
- const obj: IAsn1Encodable);
- begin
- Inherited Create(explicitly, tagNo, obj)
- end;
- constructor TBerTaggedObject.Create(tagNo: Int32);
- begin
- Inherited Create(False, tagNo, TBerSequence.Empty)
- end;
- procedure TBerTaggedObject.Encode(const derOut: TStream);
- var
- eObj: TList<IAsn1Encodable>;
- LListIDerOctetString: TCryptoLibGenericArray<IDerOctetString>;
- LListIAsn1Encodable: TCryptoLibGenericArray<IAsn1Encodable>;
- asn1OctetString: IAsn1OctetString;
- berOctetString: IBerOctetString;
- derOctetString: IDerOctetString;
- asn1Sequence: IAsn1Sequence;
- asn1Set: IAsn1Set;
- o: IAsn1Encodable;
- begin
- eObj := TList<IAsn1Encodable>.Create();
- try
- if ((derOut is TAsn1OutputStream) or (derOut is TBerOutputStream)) then
- begin
- (derOut as TDerOutputStream)
- .WriteTag(Byte(TAsn1Tags.Constructed or TAsn1Tags.Tagged), tagNo);
- (derOut as TDerOutputStream).WriteByte($80);
- if (not IsEmpty()) then
- begin
- if (not explicitly) then
- begin
- if (Supports(obj, IAsn1OctetString, asn1OctetString)) then
- begin
- if (Supports(asn1OctetString, IBerOctetString, berOctetString)) then
- begin
- LListIDerOctetString := berOctetString.GetEnumerable;
- for derOctetString in LListIDerOctetString do
- begin
- eObj.Add(derOctetString as IAsn1Encodable);
- end;
- end
- else
- begin
- berOctetString := TBerOctetString.Create
- (asn1OctetString.GetOctets());
- LListIDerOctetString := berOctetString.GetEnumerable;
- for derOctetString in LListIDerOctetString do
- begin
- eObj.Add(derOctetString as IAsn1Encodable);
- end;
- end
- end
- else if Supports(obj, IAsn1Sequence, asn1Sequence) then
- begin
- LListIAsn1Encodable := asn1Sequence.GetEnumerable;
- for o in LListIAsn1Encodable do
- begin
- eObj.Add(o);
- end;
- end
- else if Supports(obj, IAsn1Set, asn1Set) then
- begin
- LListIAsn1Encodable := asn1Set.GetEnumerable;
- for o in LListIAsn1Encodable do
- begin
- eObj.Add(o);
- end;
- end
- else
- begin
- raise ENotImplementedCryptoLibException.CreateResFmt
- (@SNotImplemented, [(obj as TAsn1Encodable).ClassName]);
- end;
- for o in eObj do
- begin
- (derOut as TDerOutputStream).WriteObject(o);
- end;
- end
- else
- begin
- (derOut as TDerOutputStream).WriteObject(obj);
- end;
- end;
- (derOut as TDerOutputStream).WriteByte($00);
- (derOut as TDerOutputStream).WriteByte($00);
- end
- else
- begin
- (Inherited Encode(derOut));
- end
- finally
- eObj.Free;
- end;
- end;
- { TBerTaggedObjectParser }
- constructor TBerTaggedObjectParser.Create(Constructed: Boolean;
- tagNumber: Int32; const parser: IAsn1StreamParser);
- begin
- F_constructed := Constructed;
- F_tagNumber := tagNumber;
- F_parser := parser;
- end;
- destructor TBerTaggedObjectParser.Destroy;
- begin
- F_parser := Nil;
- inherited Destroy;
- end;
- function TBerTaggedObjectParser.GetIsConstructed: Boolean;
- begin
- result := F_constructed;
- end;
- function TBerTaggedObjectParser.GetObjectParser(tag: Int32; isExplicit: Boolean)
- : IAsn1Convertible;
- begin
- if (isExplicit) then
- begin
- if (not F_constructed) then
- begin
- raise EIOCryptoLibException.CreateRes(@SUnConstructedTag);
- end;
- result := F_parser.ReadObject();
- Exit;
- end;
- result := F_parser.ReadImplicit(F_constructed, tag);
- end;
- function TBerTaggedObjectParser.GetTagNo: Int32;
- begin
- result := F_tagNumber;
- end;
- function TBerTaggedObjectParser.ToAsn1Object: IAsn1Object;
- begin
- try
- result := F_parser.ReadTaggedObject(F_constructed, F_tagNumber);
- except
- on e: EIOCryptoLibException do
- begin
- raise EAsn1ParsingCryptoLibException.CreateResFmt(@SParsingError,
- [e.Message]);
- end;
- end;
- end;
- { TDerBmpString }
- function TDerBmpString.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerBmpString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerBmpString;
- begin
- if (not Supports(asn1Object, IDerBmpString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerBmpString.Create(const astr: TCryptoLibByteArray);
- var
- cs: TCryptoLibCharArray;
- I: Int32;
- begin
- Inherited Create();
- if (astr = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SEmptyInput);
- end;
- System.SetLength(cs, System.length(astr) shr 1);
- I := 0;
- while I <> System.length(cs) do
- begin
- cs[I] := Char((astr[2 * I] shl 8) or (astr[2 * I + 1] and $FF));
- System.Inc(I);
- end;
- System.SetString(FStr, PChar(@cs[0]), System.length(cs));
- end;
- constructor TDerBmpString.Create(const astr: String);
- begin
- Inherited Create();
- if (astr = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SEmptyInput);
- end;
- FStr := astr;
- end;
- procedure TDerBmpString.Encode(const derOut: TStream);
- var
- c: TCryptoLibCharArray;
- b: TCryptoLibByteArray;
- I: Int32;
- begin
- c := TStringUtils.StringToCharArray(Str);
- System.SetLength(b, System.length(c) * 2);
- I := 0;
- while I <> System.length(c) do
- begin
- b[2 * I] := Byte(Ord(c[I]) shr 8);
- b[2 * I + 1] := Byte(c[I]);
- System.Inc(I);
- end;
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.BmpString, b);
- end;
- class function TDerBmpString.GetInstance(const obj: TObject): IDerBmpString;
- begin
- if ((obj = Nil) or (obj is TDerBmpString)) then
- begin
- result := obj as TDerBmpString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerBmpString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBmpString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerBmpString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerBmpString.Create(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- function TDerBmpString.GetString: String;
- begin
- result := FStr;
- end;
- { TDerBoolean }
- function TDerBoolean.GetIsTrue: Boolean;
- begin
- result := Fvalue <> 0;
- end;
- function TDerBoolean.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerBoolean;
- begin
- if (not Supports(asn1Object, IDerBoolean, other)) then
- begin
- result := System.False;
- Exit;
- end;
- result := IsTrue = other.IsTrue;
- end;
- function TDerBoolean.Asn1GetHashCode: Int32;
- begin
- result := Ord(IsTrue);
- end;
- constructor TDerBoolean.Create(const val: TCryptoLibByteArray);
- begin
- Inherited Create();
- if (System.length(val) <> 1) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInvalidValue);
- end;
- // TODO Are there any constraints on the possible byte values?
- Fvalue := val[0];
- end;
- constructor TDerBoolean.Create(Value: Boolean);
- begin
- Inherited Create();
- if Value then
- begin
- Fvalue := Byte($FF)
- end
- else
- begin
- Fvalue := Byte(0)
- end;
- end;
- procedure TDerBoolean.Encode(const derOut: TStream);
- begin
- // TODO Should we make sure the byte value is one of '0' or '0xff' here?
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Boolean,
- TCryptoLibByteArray.Create(Fvalue));
- end;
- class function TDerBoolean.FromOctetString(const Value: TCryptoLibByteArray)
- : IDerBoolean;
- var
- b: Byte;
- begin
- if (System.length(Value) <> 1) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SInvalidBooleanValue);
- end;
- b := Value[0];
- case b of
- 0:
- result := TDerBoolean.False;
- $FF:
- result := TDerBoolean.True
- else
- begin
- result := TDerBoolean.Create(Value);
- end;
- end;
- end;
- class function TDerBoolean.GetInstance(Value: Boolean): IDerBoolean;
- begin
- if Value then
- begin
- result := TDerBoolean.True;
- end
- else
- begin
- result := TDerBoolean.False;
- end;
- end;
- class function TDerBoolean.GetInstance(const obj: TObject): IDerBoolean;
- begin
- if ((obj = Nil) or (obj is TDerBoolean)) then
- begin
- Supports(obj, IDerBoolean, result);
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerBoolean.GetFalse: IDerBoolean;
- begin
- result := TDerBoolean.Create(System.False);
- end;
- class function TDerBoolean.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerBoolean;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerBoolean))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := FromOctetString((o as IAsn1OctetString).GetOctets());
- end;
- class function TDerBoolean.GetTrue: IDerBoolean;
- begin
- result := TDerBoolean.Create(System.True);
- end;
- function TDerBoolean.ToString: String;
- begin
- result := BoolToStr(IsTrue, System.True);
- end;
- { TDerEnumerated }
- function TDerEnumerated.GetBytes: TCryptoLibByteArray;
- begin
- result := Fbytes;
- end;
- function TDerEnumerated.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerEnumerated;
- begin
- if (not Supports(asn1Object, IDerEnumerated, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(bytes, other.bytes);
- end;
- function TDerEnumerated.Asn1GetHashCode: Int32;
- begin
- result := TArrayUtils.GetArrayHashCode(bytes);
- end;
- constructor TDerEnumerated.Create(val: Int32);
- begin
- Inherited Create();
- if (val < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SEnumeratedNegative);
- end;
- Fbytes := TBigInteger.ValueOf(val).ToByteArray();
- FStart := 0;
- end;
- constructor TDerEnumerated.Create(val: Int64);
- begin
- Inherited Create();
- if (val < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SEnumeratedNegative);
- end;
- Fbytes := TBigInteger.ValueOf(val).ToByteArray();
- FStart := 0;
- end;
- constructor TDerEnumerated.Create(const val: TBigInteger);
- begin
- Inherited Create();
- if (val.SignValue < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SEnumeratedNegative);
- end;
- Fbytes := val.ToByteArray();
- FStart := 0;
- end;
- constructor TDerEnumerated.Create(const bytes: TCryptoLibByteArray);
- begin
- Inherited Create();
- if (TDerInteger.IsMalformed(bytes)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SMalformedEnumerated);
- end;
- if (0 <> (bytes[0] and $80)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SEnumeratedNegative);
- end;
- Fbytes := System.Copy(bytes);
- FStart := TDerInteger.SignBytesToSkip(bytes);
- end;
- procedure TDerEnumerated.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Enumerated, Fbytes);
- end;
- class function TDerEnumerated.FromOctetString(const enc: TCryptoLibByteArray)
- : IDerEnumerated;
- var
- LValue: Int32;
- possibleMatch: IDerEnumerated;
- begin
- if (System.length(enc) > 1) then
- begin
- result := TDerEnumerated.Create(enc);
- Exit;
- end;
- if (System.length(enc) = 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SZeroLength);
- end;
- LValue := enc[0];
- if (LValue >= System.length(Fcache)) then
- begin
- result := TDerEnumerated.Create(enc);
- Exit;
- end;
- possibleMatch := Fcache[LValue];
- if (possibleMatch = Nil) then
- begin
- possibleMatch := TDerEnumerated.Create(enc);
- Fcache[LValue] := possibleMatch;
- end;
- result := possibleMatch;
- end;
- class function TDerEnumerated.GetInstance(const obj: TObject): IDerEnumerated;
- begin
- if ((obj = Nil) or (obj is TDerEnumerated)) then
- begin
- result := obj as TDerEnumerated;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerEnumerated.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerEnumerated;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if (isExplicit or (Supports(o, IDerEnumerated))) then
- begin
- result := GetInstance(o as TObject);
- Exit;
- end;
- result := FromOctetString((o as IAsn1OctetString).GetOctets());
- end;
- function TDerEnumerated.GetIntValueExact: Int32;
- var
- count: Int32;
- begin
- count := System.length(Fbytes) - FStart;
- if (count > 4) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SASN1IntegerOutOfRangeError);
- end;
- result := TDerInteger.IntValue(Fbytes, FStart, TDerInteger.SignExtSigned);
- end;
- function TDerEnumerated.GetValue: TBigInteger;
- begin
- result := TBigInteger.Create(Fbytes);
- end;
- function TDerEnumerated.HasValue(const x: TBigInteger): Boolean;
- begin
- result := (x.IsInitialized)
- // Fast check to avoid allocation
- and (TDerInteger.IntValue(Fbytes, FStart, TDerInteger.SignExtSigned)
- = x.Int32Value) and (Value.Equals(x));
- end;
- { TDerGraphicString }
- function TDerGraphicString.GetmString: TCryptoLibByteArray;
- begin
- result := FmString;
- end;
- function TDerGraphicString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerGraphicString;
- begin
- if (not Supports(asn1Object, IDerGraphicString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(mString, other.mString);
- end;
- function TDerGraphicString.Asn1GetHashCode: Int32;
- begin
- result := TArrayUtils.GetArrayHashCode(mString);
- end;
- constructor TDerGraphicString.Create(const encoding: TCryptoLibByteArray);
- begin
- Inherited Create();
- FmString := System.Copy(encoding);
- end;
- procedure TDerGraphicString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.GraphicString, mString);
- end;
- class function TDerGraphicString.GetInstance(const obj: TObject)
- : IDerGraphicString;
- begin
- if ((obj = Nil) or (obj is TDerGraphicString)) then
- begin
- result := obj as TDerGraphicString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerGraphicString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerGraphicString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerGraphicString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerGraphicString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- class function TDerGraphicString.GetInstance(const obj: TCryptoLibByteArray)
- : IDerGraphicString;
- begin
- try
- result := FromByteArray(obj) as IDerGraphicString;
- except
- on e: Exception do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SEncodingError,
- [e.Message]);
- end;
- end;
- end;
- function TDerGraphicString.GetOctets: TCryptoLibByteArray;
- begin
- result := System.Copy(mString);
- end;
- function TDerGraphicString.GetString: String;
- begin
- result := TConverters.ConvertBytesToString(mString, TEncoding.ANSI);
- end;
- { TDerExternal }
- class function TDerExternal.GetObjFromVector(const v: IAsn1EncodableVector;
- Index: Int32): IAsn1Object;
- var
- val: IAsn1Encodable;
- begin
- if (v.count <= index) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SFewObject);
- end;
- val := v[index];
- result := val.ToAsn1Object();
- end;
- class procedure TDerExternal.WriteEncodable(ms: TMemoryStream;
- const e: IAsn1Encodable);
- var
- bs: TCryptoLibByteArray;
- begin
- if (e <> Nil) then
- begin
- bs := e.GetDerEncoded();
- ms.Write(bs[0], System.length(bs));
- end;
- end;
- function TDerExternal.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerExternal;
- begin
- if (Self.Equals(asn1Object)) then
- begin
- result := True;
- Exit;
- end;
- if (not Supports(asn1Object, IDerExternal, other)) then
- begin
- result := False;
- Exit;
- end;
- result := directReference.Equals(other.directReference) and
- indirectReference.Equals(other.indirectReference) and
- dataValueDescriptor.Equals(other.dataValueDescriptor) and
- ExternalContent.Equals(other.ExternalContent);
- end;
- function TDerExternal.Asn1GetHashCode: Int32;
- var
- ret: Int32;
- begin
- ret := ExternalContent.GetHashCode();
- if (directReference <> Nil) then
- begin
- ret := ret xor directReference.GetHashCode();
- end;
- if (indirectReference <> Nil) then
- begin
- ret := ret xor indirectReference.GetHashCode();
- end;
- if (dataValueDescriptor <> Nil) then
- begin
- ret := ret xor dataValueDescriptor.GetHashCode();
- end;
- result := ret;
- end;
- constructor TDerExternal.Create(const directReference: IDerObjectIdentifier;
- const indirectReference: IDerInteger; const dataValueDescriptor: IAsn1Object;
- encoding: Int32; const externalData: IAsn1Object);
- begin
- Inherited Create();
- FdirectReference := directReference;
- FindirectReference := indirectReference;
- FdataValueDescriptor := dataValueDescriptor;
- Fencoding := encoding;
- FexternalContent := externalData.ToAsn1Object();
- end;
- constructor TDerExternal.Create(const vector: IAsn1EncodableVector);
- var
- offset: Int32;
- enc: IAsn1Object;
- derObjectIdentifier: IDerObjectIdentifier;
- derInteger: IDerInteger;
- obj: IAsn1TaggedObject;
- begin
- Inherited Create();
- offset := 0;
- enc := GetObjFromVector(vector, offset);
- if (Supports(enc, IDerObjectIdentifier, derObjectIdentifier)) then
- begin
- directReference := derObjectIdentifier;
- System.Inc(offset);
- enc := GetObjFromVector(vector, offset);
- end;
- if (Supports(enc, IDerInteger, derInteger)) then
- begin
- indirectReference := derInteger;
- System.Inc(offset);
- enc := GetObjFromVector(vector, offset);
- end;
- if (not(Supports(enc, IAsn1TaggedObject))) then
- begin
- dataValueDescriptor := enc;
- System.Inc(offset);
- enc := GetObjFromVector(vector, offset);
- end;
- if (vector.count <> (offset + 1)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SVectorTooLarge);
- end;
- if (not(Supports(enc, IAsn1TaggedObject, obj))) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SNoTaggedObjectFound);
- end;
- // Use property accessor to include check on value
- encoding := obj.tagNo;
- if ((Fencoding < 0) or (Fencoding > 2)) then
- begin
- raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidEncodingValue);
- end;
- FexternalContent := obj.GetObject();
- end;
- constructor TDerExternal.Create(const directReference: IDerObjectIdentifier;
- const indirectReference: IDerInteger; const dataValueDescriptor: IAsn1Object;
- const externalData: IDerTaggedObject);
- begin
- Create(directReference, indirectReference, dataValueDescriptor,
- externalData.tagNo, externalData.ToAsn1Object());
- end;
- procedure TDerExternal.Encode(const derOut: TStream);
- var
- ms: TMemoryStream;
- buffer: TCryptoLibByteArray;
- begin
- ms := TMemoryStream.Create();
- try
- WriteEncodable(ms, directReference);
- WriteEncodable(ms, indirectReference);
- WriteEncodable(ms, dataValueDescriptor);
- WriteEncodable(ms, TDerTaggedObject.Create(TAsn1Tags.External,
- ExternalContent));
- System.SetLength(buffer, ms.Size);
- ms.Position := 0;
- ms.Read(buffer[0], ms.Size);
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Constructed,
- TAsn1Tags.External, buffer);
- finally
- ms.Free;
- end;
- end;
- function TDerExternal.GetDataValueDescriptor: IAsn1Object;
- begin
- result := FdataValueDescriptor;
- end;
- function TDerExternal.GetDirectReference: IDerObjectIdentifier;
- begin
- result := FdirectReference;
- end;
- function TDerExternal.GetEncoding: Int32;
- begin
- result := Fencoding;
- end;
- function TDerExternal.GetExternalContent: IAsn1Object;
- begin
- result := FexternalContent;
- end;
- function TDerExternal.GetIndirectReference: IDerInteger;
- begin
- result := FindirectReference;
- end;
- procedure TDerExternal.SetDataValueDescriptor(const Value: IAsn1Object);
- begin
- FdataValueDescriptor := Value;
- end;
- procedure TDerExternal.SetDirectReference(const Value: IDerObjectIdentifier);
- begin
- FdirectReference := Value;
- end;
- procedure TDerExternal.SetEncoding(const Value: Int32);
- begin
- if ((Fencoding < 0) or (Fencoding > 2)) then
- begin
- raise EInvalidOperationCryptoLibException.CreateResFmt
- (@SInvalidEncoding, [Value]);
- end;
- Fencoding := Value;
- end;
- procedure TDerExternal.SetExternalContent(const Value: IAsn1Object);
- begin
- FexternalContent := Value;
- end;
- procedure TDerExternal.SetIndirectReference(const Value: IDerInteger);
- begin
- FindirectReference := Value;
- end;
- { TDerInteger }
- class function TDerInteger.GetAllowUnsafeInteger: Boolean;
- begin
- result := FAllowUnsafeInteger;
- end;
- class procedure TDerInteger.SetAllowUnsafeInteger(const Value: Boolean);
- begin
- FAllowUnsafeInteger := Value;
- end;
- function TDerInteger.GetBytes: TCryptoLibByteArray;
- begin
- result := Fbytes;
- end;
- class function TDerInteger.GetInstance(const obj: TObject): IDerInteger;
- begin
- if ((obj = Nil) or (obj is TDerInteger)) then
- begin
- result := obj as TDerInteger;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- function TDerInteger.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerInteger;
- begin
- if (not Supports(asn1Object, IDerInteger, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(bytes, other.bytes);
- end;
- function TDerInteger.Asn1GetHashCode: Int32;
- begin
- result := TArrayUtils.GetArrayHashCode(Fbytes);
- end;
- constructor TDerInteger.Create(const Value: TBigInteger);
- begin
- inherited Create();
- if (not Value.IsInitialized) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SValueNil);
- end;
- Fbytes := Value.ToByteArray();
- FStart := 0;
- end;
- constructor TDerInteger.Create(Value: Int32);
- begin
- inherited Create();
- Fbytes := TBigInteger.ValueOf(Value).ToByteArray();
- FStart := 0;
- end;
- constructor TDerInteger.Create(Value: Int64);
- begin
- inherited Create();
- Fbytes := TBigInteger.ValueOf(Value).ToByteArray();
- FStart := 0;
- end;
- constructor TDerInteger.Create(const bytes: TCryptoLibByteArray);
- begin
- Create(bytes, True);
- end;
- constructor TDerInteger.Create(const bytes: TCryptoLibByteArray;
- clone: Boolean);
- begin
- Inherited Create();
- if (IsMalformed(bytes)) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SMalformedInteger);
- end;
- if clone then
- begin
- Fbytes := System.Copy(bytes);
- end
- else
- begin
- Fbytes := bytes;
- end;
- FStart := SignBytesToSkip(bytes);
- end;
- class constructor TDerInteger.CreateDerInteger;
- begin
- FAllowUnsafeInteger := False;
- end;
- procedure TDerInteger.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Integer, Fbytes);
- end;
- class function TDerInteger.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerInteger;
- var
- o: IAsn1Object;
- begin
- if (obj = Nil) then
- raise EArgumentNilCryptoLibException.CreateRes(@SObjectNil);
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerInteger))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerInteger.Create(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- function TDerInteger.GetIntPositiveValueExact: Int32;
- var
- count: Int32;
- begin
- count := System.length(Fbytes) - FStart;
- if ((count > 4) or ((count = 4) and (0 <> (bytes[FStart] and $80)))) then
- begin
- raise EArithmeticCryptoLibException.CreateRes
- (@SASN1IntegerPositiveOutOfRangeError);
- end;
- result := IntValue(Fbytes, FStart, SignExtUnsigned);
- end;
- function TDerInteger.GetIntValueExact: Int32;
- var
- count: Int32;
- begin
- count := System.length(Fbytes) - FStart;
- if (count > 4) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SASN1IntegerOutOfRangeError);
- end;
- result := IntValue(Fbytes, FStart, SignExtSigned);
- end;
- function TDerInteger.GetPositiveValue: TBigInteger;
- begin
- result := TBigInteger.Create(1, Fbytes);
- end;
- function TDerInteger.GetValue: TBigInteger;
- begin
- result := TBigInteger.Create(Fbytes);
- end;
- function TDerInteger.HasValue(const x: TBigInteger): Boolean;
- begin
- result := (x.IsInitialized)
- // Fast check to avoid allocation
- and (IntValue(Fbytes, FStart, SignExtSigned) = x.Int32Value) and
- (Value.Equals(x));
- end;
- class function TDerInteger.IntValue(const bytes: TCryptoLibByteArray;
- start, signExt: Int32): Int32;
- var
- LLength, LPos, LVal: Int32;
- begin
- LLength := System.length(bytes);
- LPos := Max(start, LLength - 4);
- LVal := ShortInt(bytes[LPos]) and signExt;
- System.Inc(LPos);
- while (LPos < LLength) do
- begin
- LVal := (LVal shl 8) or bytes[LPos];
- System.Inc(LPos);
- end;
- result := LVal;
- end;
- class function TDerInteger.IsMalformed(const bytes
- : TCryptoLibByteArray): Boolean;
- begin
- case System.length(bytes) of
- 0:
- begin
- result := True;
- end;
- 1:
- begin
- result := False;
- end
- else
- begin
- result := (ShortInt(bytes[0]) = (TBits.Asr32(ShortInt(bytes[1]), 7))) and
- (not AllowUnsafeInteger);
- end;
- end;
- end;
- class function TDerInteger.SignBytesToSkip(const bytes
- : TCryptoLibByteArray): Int32;
- var
- LPos, LLast: Int32;
- begin
- LPos := 0;
- LLast := System.length(bytes) - 1;
- while ((LPos < LLast) and (ShortInt(bytes[LPos])
- = TBits.Asr32(ShortInt(bytes[LPos + 1]), 7))) do
- begin
- System.Inc(LPos);
- end;
- result := LPos;
- end;
- function TDerInteger.ToString: String;
- begin
- result := Value.ToString();
- end;
- { TDerExternalParser }
- constructor TDerExternalParser.Create(const parser: IAsn1StreamParser);
- begin
- Inherited Create();
- F_parser := parser;
- end;
- function TDerExternalParser.ReadObject: IAsn1Convertible;
- begin
- result := F_parser.ReadObject();
- end;
- function TDerExternalParser.ToAsn1Object: IAsn1Object;
- begin
- result := TDerExternal.Create(F_parser.ReadVector());
- end;
- { TDerOctetStringParser }
- constructor TDerOctetStringParser.Create(stream: TStream);
- begin
- FStream := stream;
- end;
- destructor TDerOctetStringParser.Destroy;
- begin
- FStream.Free;
- inherited Destroy;
- end;
- function TDerOctetStringParser.GetOctetStream: TStream;
- begin
- result := FStream;
- end;
- function TDerOctetStringParser.ToAsn1Object: IAsn1Object;
- begin
- try
- result := TDerOctetString.Create((FStream as TDefiniteLengthInputStream)
- .ToArray());
- except
- on e: EIOCryptoLibException do
- begin
- raise EInvalidOperationCryptoLibException.CreateResFmt(@SConvertError,
- [e.Message]);
- end;
- end;
- end;
- { TDerGeneralString }
- function TDerGeneralString.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerGeneralString.GetOctets: TCryptoLibByteArray;
- begin
- result := TConverters.ConvertStringToBytes(Str, TEncoding.ASCII);
- end;
- function TDerGeneralString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerGeneralString;
- begin
- if (not Supports(asn1Object, IDerGeneralString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerGeneralString.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.ASCII));
- end;
- constructor TDerGeneralString.Create(const Str: String);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- procedure TDerGeneralString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.GeneralString,
- GetOctets());
- end;
- class function TDerGeneralString.GetInstance(const obj: TObject)
- : IDerGeneralString;
- begin
- if ((obj = Nil) or (obj is TDerGeneralString)) then
- begin
- result := obj as TDerGeneralString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerGeneralString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerGeneralString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerGeneralString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerGeneralString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- function TDerGeneralString.GetString: String;
- begin
- result := Str;
- end;
- { TDerGenerator }
- constructor TDerGenerator.Create(const outStream: TStream);
- begin
- Inherited Create(outStream);
- end;
- constructor TDerGenerator.Create(const outStream: TStream; tagNo: Int32;
- isExplicit: Boolean);
- begin
- Inherited Create(outStream);
- F_tagged := True;
- F_isExplicit := isExplicit;
- F_tagNo := tagNo;
- end;
- class procedure TDerGenerator.WriteDerEncoded(const outStream: TStream;
- tag: Int32; const bytes: TCryptoLibByteArray);
- begin
- outStream.WriteByte(Byte(tag));
- WriteLength(outStream, System.length(bytes));
- outStream.Write(bytes[0], System.length(bytes));
- end;
- procedure TDerGenerator.WriteDerEncoded(tag: Int32;
- const bytes: TCryptoLibByteArray);
- var
- tagNum, newTag: Int32;
- bOut: TMemoryStream;
- temp: TCryptoLibByteArray;
- begin
- if (F_tagged) then
- begin
- tagNum := F_tagNo or TAsn1Tags.Tagged;
- if (F_isExplicit) then
- begin
- newTag := F_tagNo or TAsn1Tags.Constructed or TAsn1Tags.Tagged;
- bOut := TMemoryStream.Create();
- try
- WriteDerEncoded(bOut, tag, bytes);
- bOut.Position := 0;
- System.SetLength(temp, bOut.Size);
- bOut.Read(temp[0], bOut.Size);
- WriteDerEncoded(&Out, newTag, temp);
- finally
- bOut.Free;
- end;
- end
- else
- begin
- if ((tag and TAsn1Tags.Constructed) <> 0) then
- begin
- tagNum := tagNum or TAsn1Tags.Constructed;
- end;
- WriteDerEncoded(&Out, tagNum, bytes);
- end;
- end
- else
- begin
- WriteDerEncoded(&Out, tag, bytes);
- end;
- end;
- class procedure TDerGenerator.WriteDerEncoded(const outStr: TStream; tag: Int32;
- const inStr: TStream);
- begin
- WriteDerEncoded(outStr, tag, TStreamUtils.ReadAll(inStr));
- end;
- class procedure TDerGenerator.WriteLength(const outStr: TStream; length: Int32);
- var
- Size, val, I: Int32;
- begin
- if (length > 127) then
- begin
- Size := 1;
- val := length;
- val := TBits.Asr32(val, 8);
- while (val <> 0) do
- begin
- System.Inc(Size);
- val := TBits.Asr32(val, 8);
- end;
- outStr.WriteByte(Byte(Size or $80));
- I := (Size - 1) * 8;
- while I >= 0 do
- begin
- outStr.WriteByte(Byte(TBits.Asr32(length, I)));
- System.Dec(I, 8);
- end;
- end
- else
- begin
- outStr.WriteByte(Byte(length));
- end;
- end;
- { TDerIA5String }
- function TDerIA5String.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerIA5String.GetOctets: TCryptoLibByteArray;
- begin
- result := TConverters.ConvertStringToBytes(Str, TEncoding.ASCII);
- end;
- class function TDerIA5String.IsIA5String(const Str: String): Boolean;
- var
- ch: Char;
- begin
- for ch in Str do
- begin
- if (Ord(ch) > $007F) then
- begin
- result := False;
- Exit;
- end;
- end;
- result := True;
- end;
- function TDerIA5String.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerIA5String;
- begin
- if (not Supports(asn1Object, IDerIA5String, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- function TDerIA5String.Asn1GetHashCode: Int32;
- begin
- result := TStringUtils.GetStringHashCode(FStr);
- end;
- constructor TDerIA5String.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.ASCII), False);
- end;
- constructor TDerIA5String.Create(const Str: String);
- begin
- Create(Str, False);
- end;
- constructor TDerIA5String.Create(const Str: String; validate: Boolean);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- if (validate and (not IsIA5String(Str))) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SIllegalCharacters);
- end;
- FStr := Str;
- end;
- procedure TDerIA5String.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.IA5String, GetOctets());
- end;
- class function TDerIA5String.GetInstance(const obj: TObject): IDerIA5String;
- begin
- if ((obj = Nil) or (obj is TDerIA5String)) then
- begin
- result := obj as TDerIA5String;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerIA5String.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerIA5String;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerIA5String))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerIA5String.Create(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- function TDerIA5String.GetString: String;
- begin
- result := Str;
- end;
- { TDerNumericString }
- function TDerNumericString.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerNumericString.GetOctets: TCryptoLibByteArray;
- begin
- result := TConverters.ConvertStringToBytes(Str, TEncoding.ASCII);
- end;
- class function TDerNumericString.IsNumericString(const Str: String): Boolean;
- var
- ch: Char;
- begin
- for ch in Str do
- begin
- // char.IsDigit(ch)
- if ((Ord(ch) > $007F) or ((ch <> ' ') and (not CharInSet(ch, ['0' .. '9']))))
- then
- begin
- result := False;
- Exit;
- end;
- end;
- result := True;
- end;
- function TDerNumericString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerNumericString;
- begin
- if (not Supports(asn1Object, IDerNumericString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerNumericString.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.ASCII), False);
- end;
- constructor TDerNumericString.Create(const Str: String);
- begin
- Create(Str, False);
- end;
- constructor TDerNumericString.Create(const Str: String; validate: Boolean);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- if (validate and (not IsNumericString(Str))) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SIllegalCharacters);
- end;
- FStr := Str;
- end;
- procedure TDerNumericString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.NumericString,
- GetOctets());
- end;
- class function TDerNumericString.GetInstance(const obj: TObject)
- : IDerNumericString;
- begin
- if ((obj = Nil) or (obj is TDerNumericString)) then
- begin
- result := obj as TDerNumericString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerNumericString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerNumericString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerNumericString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerNumericString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- function TDerNumericString.GetString: String;
- begin
- result := Str;
- end;
- { TDerPrintableString }
- function TDerPrintableString.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerPrintableString.GetString: String;
- begin
- result := Str;
- end;
- function TDerPrintableString.GetOctets: TCryptoLibByteArray;
- begin
- result := TConverters.ConvertStringToBytes(Str, TEncoding.ASCII);
- end;
- class function TDerPrintableString.IsPrintableString(const Str: String)
- : Boolean;
- var
- ch: Char;
- begin
- for ch in Str do
- begin
- if ((Ord(ch) > $007F)) then
- begin
- result := False;
- Exit;
- end;
- // if (char.IsLetterOrDigit(ch))
- if CharInSet(ch, ['a' .. 'z', 'A' .. 'Z', '0' .. '9']) then
- begin
- continue;
- end;
- case IndexStr(UnicodeString(ch), [''' ''', '\', '(', ')', '+', '-', '.',
- ':', '=', '?', '/', ',']) of
- 0 .. 11:
- begin
- continue;
- end;
- end;
- result := False;
- Exit;
- end;
- result := True;
- end;
- function TDerPrintableString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerPrintableString;
- begin
- if (not Supports(asn1Object, IDerPrintableString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerPrintableString.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.ASCII), False);
- end;
- constructor TDerPrintableString.Create(const Str: String);
- begin
- Create(Str, False);
- end;
- constructor TDerPrintableString.Create(const Str: String; validate: Boolean);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- if (validate and (not IsPrintableString(Str))) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SIllegalCharacters);
- end;
- FStr := Str;
- end;
- procedure TDerPrintableString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.PrintableString,
- GetOctets());
- end;
- class function TDerPrintableString.GetInstance(const obj: TObject)
- : IDerPrintableString;
- begin
- if ((obj = Nil) or (obj is TDerPrintableString)) then
- begin
- result := obj as TDerPrintableString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerPrintableString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerPrintableString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerPrintableString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerPrintableString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- { TDerSequenceGenerator }
- procedure TDerSequenceGenerator.AddObject(const obj: IAsn1Encodable);
- var
- temp: TDerOutputStream;
- begin
- temp := TDerOutputStream.Create(F_bOut);
- try
- temp.WriteObject(obj);
- finally
- temp.Free;
- end;
- end;
- procedure TDerSequenceGenerator.Close;
- var
- temp: TCryptoLibByteArray;
- begin
- F_bOut.Position := 0;
- System.SetLength(temp, F_bOut.Size);
- F_bOut.Read(temp[0], F_bOut.Size);
- WriteDerEncoded(TAsn1Tags.Constructed or TAsn1Tags.Sequence, temp);
- end;
- constructor TDerSequenceGenerator.Create(outStream: TStream);
- begin
- Inherited Create(outStream);
- F_bOut := TMemoryStream.Create();
- end;
- constructor TDerSequenceGenerator.Create(outStream: TStream; tagNo: Int32;
- isExplicit: Boolean);
- begin
- Inherited Create(outStream, tagNo, isExplicit);
- F_bOut := TMemoryStream.Create();
- end;
- destructor TDerSequenceGenerator.Destroy;
- begin
- F_bOut.Free;
- inherited Destroy;
- end;
- function TDerSequenceGenerator.GetRawOutputStream: TStream;
- begin
- result := F_bOut;
- end;
- { TDerT61String }
- class function TDerT61String.GetEncoding: TEncoding;
- begin
- result := TEncoding.GetEncoding('iso-8859-1');
- end;
- function TDerT61String.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerT61String.GetOctets: TCryptoLibByteArray;
- var
- LEncoding: TEncoding;
- begin
- LEncoding := TDerT61String.GetEncoding();
- try
- result := TConverters.ConvertStringToBytes(Str, LEncoding);
- finally
- LEncoding.Free;
- end;
- end;
- function TDerT61String.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerT61String;
- begin
- if (not Supports(asn1Object, IDerT61String, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerT61String.Create(const Str: TCryptoLibByteArray);
- var
- LEncoding: TEncoding;
- begin
- Inherited Create();
- LEncoding := TDerT61String.GetEncoding();
- try
- Create(TConverters.ConvertBytesToString(Str, LEncoding));
- finally
- LEncoding.Free;
- end;
- end;
- constructor TDerT61String.Create(const Str: String);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- procedure TDerT61String.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.T61String, GetOctets());
- end;
- class function TDerT61String.GetInstance(const obj: TObject): IDerT61String;
- begin
- if ((obj = Nil) or (obj is TDerT61String)) then
- begin
- result := obj as TDerT61String;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerT61String.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerT61String;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerT61String))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerT61String.Create(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- function TDerT61String.GetString: String;
- begin
- result := Str;
- end;
- { TDerUniversalString }
- function TDerUniversalString.GetStr: TCryptoLibByteArray;
- begin
- result := FStr;
- end;
- function TDerUniversalString.GetOctets: TCryptoLibByteArray;
- begin
- result := System.Copy(Str);
- end;
- function TDerUniversalString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerUniversalString;
- begin
- if (not Supports(asn1Object, IDerUniversalString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(Str, other.Str);
- end;
- constructor TDerUniversalString.Create(const Str: TCryptoLibByteArray);
- begin
- Inherited Create();
- if (Str = Nil) then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- procedure TDerUniversalString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.UniversalString, Str);
- end;
- class function TDerUniversalString.GetInstance(const obj: TObject)
- : IDerUniversalString;
- begin
- if ((obj = Nil) or (obj is TDerUniversalString)) then
- begin
- result := obj as TDerUniversalString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerUniversalString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerUniversalString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerUniversalString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerUniversalString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- function TDerUniversalString.GetString: String;
- var
- buffer: TStringList;
- I: Int32;
- enc: TCryptoLibByteArray;
- ubyte: UInt32;
- begin
- buffer := TStringList.Create();
- buffer.LineBreak := '';
- enc := GetDerEncoded();
- buffer.Add('#');
- I := 0;
- try
- while I <> System.length(enc) do
- begin
- ubyte := enc[I];
- buffer.Add(FTable[(ubyte shr 4) and $F]);
- buffer.Add(FTable[enc[I] and $F]);
- System.Inc(I);
- end;
- result := buffer.Text;
- finally
- buffer.Free;
- end;
- end;
- { TDerUtf8String }
- function TDerUtf8String.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerUtf8String.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerUtf8String;
- begin
- if (not Supports(asn1Object, IDerUtf8String, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- constructor TDerUtf8String.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.UTF8));
- end;
- constructor TDerUtf8String.Create(const Str: String);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- procedure TDerUtf8String.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.Utf8String,
- TConverters.ConvertStringToBytes(Str, TEncoding.UTF8));
- end;
- class function TDerUtf8String.GetInstance(const obj: TObject): IDerUtf8String;
- begin
- if ((obj = Nil) or (obj is TDerUtf8String)) then
- begin
- result := obj as TDerUtf8String;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerUtf8String.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerUtf8String;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerUtf8String))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerUtf8String.Create(TAsn1OctetString.GetInstance(o as TAsn1Object)
- .GetOctets());
- end;
- function TDerUtf8String.GetString: String;
- begin
- result := Str;
- end;
- { TDerVideotexString }
- function TDerVideotexString.GetmString: TCryptoLibByteArray;
- begin
- result := FmString;
- end;
- function TDerVideotexString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerVideotexString;
- begin
- if (not Supports(asn1Object, IDerVideotexString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := TArrayUtils.AreEqual(mString, other.mString);
- end;
- function TDerVideotexString.Asn1GetHashCode: Int32;
- begin
- result := TArrayUtils.GetArrayHashCode(mString);
- end;
- constructor TDerVideotexString.Create(const encoding: TCryptoLibByteArray);
- begin
- Inherited Create();
- FmString := System.Copy(encoding);
- end;
- procedure TDerVideotexString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.VideotexString, mString);
- end;
- class function TDerVideotexString.GetInstance(const obj: TObject)
- : IDerVideotexString;
- begin
- if ((obj = Nil) or (obj is TDerVideotexString)) then
- begin
- result := obj as TDerVideotexString;
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- class function TDerVideotexString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerVideotexString;
- var
- o: IAsn1Object;
- begin
- o := obj.GetObject();
- if ((isExplicit) or (Supports(o, IDerVideotexString))) then
- begin
- result := GetInstance(o as TAsn1Object);
- Exit;
- end;
- result := TDerVideotexString.Create
- (TAsn1OctetString.GetInstance(o as TAsn1Object).GetOctets());
- end;
- class function TDerVideotexString.GetInstance(const obj: TCryptoLibByteArray)
- : IDerVideotexString;
- begin
- try
- result := FromByteArray(obj) as IDerVideotexString;
- except
- on e: Exception do
- begin
- raise EArgumentCryptoLibException.CreateResFmt(@SEncodingError,
- [e.Message]);
- end;
- end;
- end;
- function TDerVideotexString.GetOctets: TCryptoLibByteArray;
- begin
- result := System.Copy(mString);
- end;
- function TDerVideotexString.GetString: String;
- begin
- result := TConverters.ConvertBytesToString(mString, TEncoding.ANSI)
- end;
- { TDerVisibleString }
- function TDerVisibleString.GetStr: String;
- begin
- result := FStr;
- end;
- function TDerVisibleString.GetOctets: TCryptoLibByteArray;
- begin
- result := TConverters.ConvertStringToBytes(Str, TEncoding.ASCII);
- end;
- function TDerVisibleString.Asn1Equals(const asn1Object: IAsn1Object): Boolean;
- var
- other: IDerVisibleString;
- begin
- if (not Supports(asn1Object, IDerVisibleString, other)) then
- begin
- result := False;
- Exit;
- end;
- result := Str = other.Str;
- end;
- function TDerVisibleString.Asn1GetHashCode: Int32;
- begin
- result := TStringUtils.GetStringHashCode(FStr);
- end;
- constructor TDerVisibleString.Create(const Str: TCryptoLibByteArray);
- begin
- Create(TConverters.ConvertBytesToString(Str, TEncoding.ASCII));
- end;
- constructor TDerVisibleString.Create(const Str: String);
- begin
- Inherited Create();
- if (Str = '') then
- begin
- raise EArgumentNilCryptoLibException.CreateRes(@SStrNil);
- end;
- FStr := Str;
- end;
- procedure TDerVisibleString.Encode(const derOut: TStream);
- begin
- (derOut as TDerOutputStream).WriteEncoded(TAsn1Tags.VisibleString,
- GetOctets());
- end;
- class function TDerVisibleString.GetInstance(const obj: TObject)
- : IDerVisibleString;
- var
- asn1OctetString: IAsn1OctetString;
- asn1TaggedObject: IAsn1TaggedObject;
- begin
- if ((obj = Nil) or (obj is TDerVisibleString)) then
- begin
- result := obj as TDerVisibleString;
- Exit;
- end;
- if Supports(obj, IAsn1OctetString, asn1OctetString) then
- begin
- result := TDerVisibleString.Create(asn1OctetString.GetOctets());
- Exit;
- end;
- if Supports(obj, IAsn1TaggedObject, asn1TaggedObject) then
- begin
- result := GetInstance(asn1TaggedObject.GetObject() as TAsn1Object);
- Exit;
- end;
- raise EArgumentCryptoLibException.CreateResFmt(@SIllegalObject,
- [obj.ClassName]);
- end;
- {$IFNDEF _FIXINSIGHT_}
- class function TDerVisibleString.GetInstance(const obj: IAsn1TaggedObject;
- isExplicit: Boolean): IDerVisibleString;
- begin
- result := GetInstance(obj.GetObject() as TAsn1Object);
- end;
- {$ENDIF}
- function TDerVisibleString.GetString: String;
- begin
- result := Str;
- end;
- end.
|