1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040 |
- /*
- * Elliptic-curve crypto module for PuTTY
- * Implements the three required curves, no optional curves
- *
- * NOTE: Only curves on prime field are handled by the maths functions
- * in Weierstrass form using Jacobian co-ordinates.
- *
- * Montgomery form curves are supported for DH. (Curve25519)
- *
- * Edwards form curves are supported for DSA. (Ed25519)
- */
- /*
- * References:
- *
- * Elliptic curves in SSH are specified in RFC 5656:
- * http://tools.ietf.org/html/rfc5656
- *
- * That specification delegates details of public key formatting and a
- * lot of underlying mechanism to SEC 1:
- * http://www.secg.org/sec1-v2.pdf
- *
- * Montgomery maths from:
- * Handbook of elliptic and hyperelliptic curve cryptography, Chapter 13
- * http://cs.ucsb.edu/~koc/ccs130h/2013/EllipticHyperelliptic-CohenFrey.pdf
- *
- * Curve25519 spec from libssh (with reference to other things in the
- * libssh code):
- * https://git.libssh.org/users/aris/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
- *
- * Edwards DSA:
- * http://ed25519.cr.yp.to/ed25519-20110926.pdf
- */
- #include <stdlib.h>
- #include <assert.h>
- #include "ssh.h"
- /* ----------------------------------------------------------------------
- * Elliptic curve definitions
- */
- static void initialise_wcurve(struct ec_curve *curve, int bits,
- const unsigned char *p,
- const unsigned char *a, const unsigned char *b,
- const unsigned char *n, const unsigned char *Gx,
- const unsigned char *Gy)
- {
- int length = bits / 8;
- if (bits % 8) ++length;
- curve->type = EC_WEIERSTRASS;
- curve->fieldBits = bits;
- curve->p = bignum_from_bytes(p, length);
- /* Curve co-efficients */
- curve->w.a = bignum_from_bytes(a, length);
- curve->w.b = bignum_from_bytes(b, length);
- /* Group order and generator */
- curve->w.n = bignum_from_bytes(n, length);
- curve->w.G.x = bignum_from_bytes(Gx, length);
- curve->w.G.y = bignum_from_bytes(Gy, length);
- curve->w.G.curve = curve;
- curve->w.G.infinity = 0;
- }
- static void initialise_mcurve(struct ec_curve *curve, int bits,
- const unsigned char *p,
- const unsigned char *a, const unsigned char *b,
- const unsigned char *Gx)
- {
- int length = bits / 8;
- if (bits % 8) ++length;
- curve->type = EC_MONTGOMERY;
- curve->fieldBits = bits;
- curve->p = bignum_from_bytes(p, length);
- /* Curve co-efficients */
- curve->m.a = bignum_from_bytes(a, length);
- curve->m.b = bignum_from_bytes(b, length);
- /* Generator */
- curve->m.G.x = bignum_from_bytes(Gx, length);
- curve->m.G.y = NULL;
- curve->m.G.z = NULL;
- curve->m.G.curve = curve;
- curve->m.G.infinity = 0;
- }
- static void initialise_ecurve(struct ec_curve *curve, int bits,
- const unsigned char *p,
- const unsigned char *l, const unsigned char *d,
- const unsigned char *Bx, const unsigned char *By)
- {
- int length = bits / 8;
- if (bits % 8) ++length;
- curve->type = EC_EDWARDS;
- curve->fieldBits = bits;
- curve->p = bignum_from_bytes(p, length);
- /* Curve co-efficients */
- curve->e.l = bignum_from_bytes(l, length);
- curve->e.d = bignum_from_bytes(d, length);
- /* Group order and generator */
- curve->e.B.x = bignum_from_bytes(Bx, length);
- curve->e.B.y = bignum_from_bytes(By, length);
- curve->e.B.curve = curve;
- curve->e.B.infinity = 0;
- }
- static struct ec_curve *ec_p256(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char p[] = {
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char a[] = {
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc
- };
- static const unsigned char b[] = {
- 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7,
- 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc,
- 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6,
- 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b
- };
- static const unsigned char n[] = {
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
- 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51
- };
- static const unsigned char Gx[] = {
- 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
- 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2,
- 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
- 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96
- };
- static const unsigned char Gy[] = {
- 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b,
- 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
- 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
- 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5
- };
- initialise_wcurve(&curve, 256, p, a, b, n, Gx, Gy);
- curve.textname = curve.name = "nistp256";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- static struct ec_curve *ec_p384(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char p[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char a[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc
- };
- static const unsigned char b[] = {
- 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4,
- 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19,
- 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12,
- 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a,
- 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d,
- 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef
- };
- static const unsigned char n[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,
- 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,
- 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73
- };
- static const unsigned char Gx[] = {
- 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37,
- 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74,
- 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98,
- 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38,
- 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c,
- 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7
- };
- static const unsigned char Gy[] = {
- 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f,
- 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29,
- 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
- 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0,
- 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d,
- 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f
- };
- initialise_wcurve(&curve, 384, p, a, b, n, Gx, Gy);
- curve.textname = curve.name = "nistp384";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- static struct ec_curve *ec_p521(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char p[] = {
- 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff
- };
- static const unsigned char a[] = {
- 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfc
- };
- static const unsigned char b[] = {
- 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c,
- 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
- 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
- 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
- 0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
- 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
- 0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
- 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
- 0x3f, 0x00
- };
- static const unsigned char n[] = {
- 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
- 0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
- 0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
- 0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
- 0x64, 0x09
- };
- static const unsigned char Gx[] = {
- 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
- 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
- 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
- 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
- 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
- 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
- 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
- 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
- 0xbd, 0x66
- };
- static const unsigned char Gy[] = {
- 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
- 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
- 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
- 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
- 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
- 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
- 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
- 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
- 0x66, 0x50
- };
- initialise_wcurve(&curve, 521, p, a, b, n, Gx, Gy);
- curve.textname = curve.name = "nistp521";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- static struct ec_curve *ec_curve25519(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char p[] = {
- 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed
- };
- static const unsigned char a[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6d, 0x06
- };
- static const unsigned char b[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- };
- static const unsigned char gx[32] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09
- };
- initialise_mcurve(&curve, 256, p, a, b, gx);
- /* This curve doesn't need a name, because it's never used in
- * any format that embeds the curve name */
- curve.name = NULL;
- curve.textname = "Curve25519";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- static struct ec_curve *ec_curve448(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char p[56] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- };
- static const unsigned char a[56] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x62, 0xa6,
- };
- static const unsigned char b[56] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- };
- static const unsigned char gx[56] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
- };
- initialise_mcurve(&curve, 448, p, a, b, gx);
- /* This curve doesn't need a name, because it's never used in
- * any format that embeds the curve name */
- curve.name = NULL;
- curve.textname = "Curve448";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- static struct ec_curve *ec_ed25519(void)
- {
- static struct ec_curve curve = { 0 };
- static unsigned char initialised = 0;
- if (!initialised)
- {
- static const unsigned char q[] = {
- 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed
- };
- static const unsigned char l[32] = {
- 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6,
- 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed
- };
- static const unsigned char d[32] = {
- 0x52, 0x03, 0x6c, 0xee, 0x2b, 0x6f, 0xfe, 0x73,
- 0x8c, 0xc7, 0x40, 0x79, 0x77, 0x79, 0xe8, 0x98,
- 0x00, 0x70, 0x0a, 0x4d, 0x41, 0x41, 0xd8, 0xab,
- 0x75, 0xeb, 0x4d, 0xca, 0x13, 0x59, 0x78, 0xa3
- };
- static const unsigned char Bx[32] = {
- 0x21, 0x69, 0x36, 0xd3, 0xcd, 0x6e, 0x53, 0xfe,
- 0xc0, 0xa4, 0xe2, 0x31, 0xfd, 0xd6, 0xdc, 0x5c,
- 0x69, 0x2c, 0xc7, 0x60, 0x95, 0x25, 0xa7, 0xb2,
- 0xc9, 0x56, 0x2d, 0x60, 0x8f, 0x25, 0xd5, 0x1a
- };
- static const unsigned char By[32] = {
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
- 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x58
- };
- /* This curve doesn't need a name, because it's never used in
- * any format that embeds the curve name */
- curve.name = NULL;
- initialise_ecurve(&curve, 256, q, l, d, Bx, By);
- curve.textname = "Ed25519";
- /* Now initialised, no need to do it again */
- initialised = 1;
- }
- return &curve;
- }
- /* Return 1 if a is -3 % p, otherwise return 0
- * This is used because there are some maths optimisations */
- static int ec_aminus3(const struct ec_curve *curve)
- {
- int ret;
- Bignum _p;
- if (curve->type != EC_WEIERSTRASS) {
- return 0;
- }
- _p = bignum_add_long(curve->w.a, 3);
- ret = !bignum_cmp(curve->p, _p);
- freebn(_p);
- return ret;
- }
- /* ----------------------------------------------------------------------
- * Elliptic curve field maths
- */
- static Bignum ecf_add(const Bignum a, const Bignum b,
- const struct ec_curve *curve)
- {
- Bignum a1, b1, ab, ret;
- a1 = bigmod(a, curve->p);
- b1 = bigmod(b, curve->p);
- ab = bigadd(a1, b1);
- freebn(a1);
- freebn(b1);
- ret = bigmod(ab, curve->p);
- freebn(ab);
- return ret;
- }
- static Bignum ecf_square(const Bignum a, const struct ec_curve *curve)
- {
- return modmul(a, a, curve->p);
- }
- static Bignum ecf_treble(const Bignum a, const struct ec_curve *curve)
- {
- Bignum ret, tmp;
- /* Double */
- tmp = bignum_lshift(a, 1);
- /* Add itself (i.e. treble) */
- ret = bigadd(tmp, a);
- freebn(tmp);
- /* Normalise */
- while (bignum_cmp(ret, curve->p) >= 0)
- {
- tmp = bigsub(ret, curve->p);
- assert(tmp);
- freebn(ret);
- ret = tmp;
- }
- return ret;
- }
- static Bignum ecf_double(const Bignum a, const struct ec_curve *curve)
- {
- Bignum ret = bignum_lshift(a, 1);
- if (bignum_cmp(ret, curve->p) >= 0)
- {
- Bignum tmp = bigsub(ret, curve->p);
- assert(tmp);
- freebn(ret);
- return tmp;
- }
- else
- {
- return ret;
- }
- }
- /* ----------------------------------------------------------------------
- * Memory functions
- */
- void ec_point_free(struct ec_point *point)
- {
- if (point == NULL) return;
- point->curve = 0;
- if (point->x) freebn(point->x);
- if (point->y) freebn(point->y);
- if (point->z) freebn(point->z);
- point->infinity = 0;
- sfree(point);
- }
- static struct ec_point *ec_point_new(const struct ec_curve *curve,
- const Bignum x, const Bignum y, const Bignum z,
- unsigned char infinity)
- {
- struct ec_point *point = snewn(1, struct ec_point);
- point->curve = curve;
- point->x = x;
- point->y = y;
- point->z = z;
- point->infinity = infinity ? 1 : 0;
- return point;
- }
- static struct ec_point *ec_point_copy(const struct ec_point *a)
- {
- if (a == NULL) return NULL;
- return ec_point_new(a->curve,
- a->x ? copybn(a->x) : NULL,
- a->y ? copybn(a->y) : NULL,
- a->z ? copybn(a->z) : NULL,
- a->infinity);
- }
- static int ec_point_verify(const struct ec_point *a)
- {
- if (a->infinity) {
- return 1;
- } else if (a->curve->type == EC_EDWARDS) {
- /* Check y^2 - x^2 - 1 - d * x^2 * y^2 == 0 */
- Bignum y2, x2, tmp, tmp2, tmp3;
- int ret;
- y2 = ecf_square(a->y, a->curve);
- x2 = ecf_square(a->x, a->curve);
- tmp = modmul(a->curve->e.d, x2, a->curve->p);
- tmp2 = modmul(tmp, y2, a->curve->p);
- freebn(tmp);
- tmp = modsub(y2, x2, a->curve->p);
- freebn(y2);
- freebn(x2);
- tmp3 = modsub(tmp, tmp2, a->curve->p);
- freebn(tmp);
- freebn(tmp2);
- ret = !bignum_cmp(tmp3, One);
- freebn(tmp3);
- return ret;
- } else if (a->curve->type == EC_WEIERSTRASS) {
- /* Verify y^2 = x^3 + ax + b */
- int ret = 0;
- Bignum lhs = NULL, x3 = NULL, ax = NULL, x3ax = NULL, x3axm = NULL, x3axb = NULL, rhs = NULL;
- Bignum Three = bignum_from_long(3);
- lhs = modmul(a->y, a->y, a->curve->p);
- /* This uses montgomery multiplication to optimise */
- x3 = modpow(a->x, Three, a->curve->p);
- freebn(Three);
- ax = modmul(a->curve->w.a, a->x, a->curve->p);
- x3ax = bigadd(x3, ax);
- freebn(x3); x3 = NULL;
- freebn(ax); ax = NULL;
- x3axm = bigmod(x3ax, a->curve->p);
- freebn(x3ax); x3ax = NULL;
- x3axb = bigadd(x3axm, a->curve->w.b);
- freebn(x3axm); x3axm = NULL;
- rhs = bigmod(x3axb, a->curve->p);
- freebn(x3axb);
- ret = bignum_cmp(lhs, rhs) ? 0 : 1;
- freebn(lhs);
- freebn(rhs);
- return ret;
- } else {
- return 0;
- }
- }
- /* ----------------------------------------------------------------------
- * Elliptic curve point maths
- */
- /* Returns 1 on success and 0 on memory error */
- static int ecp_normalise(struct ec_point *a)
- {
- if (!a) {
- /* No point */
- return 0;
- }
- if (a->infinity) {
- /* Point is at infinity - i.e. normalised */
- return 1;
- }
- if (a->curve->type == EC_WEIERSTRASS) {
- /* In Jacobian Coordinates the triple (X, Y, Z) represents
- the affine point (X / Z^2, Y / Z^3) */
- Bignum Z2, Z2inv, Z3, Z3inv, tx, ty;
- if (!a->x || !a->y) {
- /* No point defined */
- return 0;
- } else if (!a->z) {
- /* Already normalised */
- return 1;
- }
- Z2 = ecf_square(a->z, a->curve);
- Z2inv = modinv(Z2, a->curve->p);
- if (!Z2inv) {
- freebn(Z2);
- return 0;
- }
- tx = modmul(a->x, Z2inv, a->curve->p);
- freebn(Z2inv);
- Z3 = modmul(Z2, a->z, a->curve->p);
- freebn(Z2);
- Z3inv = modinv(Z3, a->curve->p);
- freebn(Z3);
- if (!Z3inv) {
- freebn(tx);
- return 0;
- }
- ty = modmul(a->y, Z3inv, a->curve->p);
- freebn(Z3inv);
- freebn(a->x);
- a->x = tx;
- freebn(a->y);
- a->y = ty;
- freebn(a->z);
- a->z = NULL;
- return 1;
- } else if (a->curve->type == EC_MONTGOMERY) {
- /* In Montgomery (X : Z) represents the x co-ord (X / Z, ?) */
- Bignum tmp, tmp2;
- if (!a->x) {
- /* No point defined */
- return 0;
- } else if (!a->z) {
- /* Already normalised */
- return 1;
- }
- tmp = modinv(a->z, a->curve->p);
- if (!tmp) {
- return 0;
- }
- tmp2 = modmul(a->x, tmp, a->curve->p);
- freebn(tmp);
- freebn(a->z);
- a->z = NULL;
- freebn(a->x);
- a->x = tmp2;
- return 1;
- } else if (a->curve->type == EC_EDWARDS) {
- /* Always normalised */
- return 1;
- } else {
- return 0;
- }
- }
- static struct ec_point *ecp_doublew(const struct ec_point *a, const int aminus3)
- {
- Bignum S, M, outx, outy, outz;
- if (bignum_cmp(a->y, Zero) == 0)
- {
- /* Identity */
- return ec_point_new(a->curve, NULL, NULL, NULL, 1);
- }
- /* S = 4*X*Y^2 */
- {
- Bignum Y2, XY2, _2XY2;
- Y2 = ecf_square(a->y, a->curve);
- XY2 = modmul(a->x, Y2, a->curve->p);
- freebn(Y2);
- _2XY2 = ecf_double(XY2, a->curve);
- freebn(XY2);
- S = ecf_double(_2XY2, a->curve);
- freebn(_2XY2);
- }
- /* Faster calculation if a = -3 */
- if (aminus3) {
- /* if a = -3, then M can also be calculated as M = 3*(X + Z^2)*(X - Z^2) */
- Bignum Z2, XpZ2, XmZ2, second;
- if (a->z == NULL) {
- Z2 = copybn(One);
- } else {
- Z2 = ecf_square(a->z, a->curve);
- }
- XpZ2 = ecf_add(a->x, Z2, a->curve);
- XmZ2 = modsub(a->x, Z2, a->curve->p);
- freebn(Z2);
- second = modmul(XpZ2, XmZ2, a->curve->p);
- freebn(XpZ2);
- freebn(XmZ2);
- M = ecf_treble(second, a->curve);
- freebn(second);
- } else {
- /* M = 3*X^2 + a*Z^4 */
- Bignum _3X2, X2, aZ4;
- if (a->z == NULL) {
- aZ4 = copybn(a->curve->w.a);
- } else {
- Bignum Z2, Z4;
- Z2 = ecf_square(a->z, a->curve);
- Z4 = ecf_square(Z2, a->curve);
- freebn(Z2);
- aZ4 = modmul(a->curve->w.a, Z4, a->curve->p);
- freebn(Z4);
- }
- X2 = modmul(a->x, a->x, a->curve->p);
- _3X2 = ecf_treble(X2, a->curve);
- freebn(X2);
- M = ecf_add(_3X2, aZ4, a->curve);
- freebn(_3X2);
- freebn(aZ4);
- }
- /* X' = M^2 - 2*S */
- {
- Bignum M2, _2S;
- M2 = ecf_square(M, a->curve);
- _2S = ecf_double(S, a->curve);
- outx = modsub(M2, _2S, a->curve->p);
- freebn(M2);
- freebn(_2S);
- }
- /* Y' = M*(S - X') - 8*Y^4 */
- {
- Bignum SX, MSX, Eight, Y2, Y4, _8Y4;
- SX = modsub(S, outx, a->curve->p);
- freebn(S);
- MSX = modmul(M, SX, a->curve->p);
- freebn(SX);
- freebn(M);
- Y2 = ecf_square(a->y, a->curve);
- Y4 = ecf_square(Y2, a->curve);
- freebn(Y2);
- Eight = bignum_from_long(8);
- _8Y4 = modmul(Eight, Y4, a->curve->p);
- freebn(Eight);
- freebn(Y4);
- outy = modsub(MSX, _8Y4, a->curve->p);
- freebn(MSX);
- freebn(_8Y4);
- }
- /* Z' = 2*Y*Z */
- {
- Bignum YZ;
- if (a->z == NULL) {
- YZ = copybn(a->y);
- } else {
- YZ = modmul(a->y, a->z, a->curve->p);
- }
- outz = ecf_double(YZ, a->curve);
- freebn(YZ);
- }
- return ec_point_new(a->curve, outx, outy, outz, 0);
- }
- static struct ec_point *ecp_doublem(const struct ec_point *a)
- {
- Bignum z, outx, outz, xpz, xmz;
- z = a->z;
- if (!z) {
- z = One;
- }
- /* 4xz = (x + z)^2 - (x - z)^2 */
- {
- Bignum tmp;
- tmp = ecf_add(a->x, z, a->curve);
- xpz = ecf_square(tmp, a->curve);
- freebn(tmp);
- tmp = modsub(a->x, z, a->curve->p);
- xmz = ecf_square(tmp, a->curve);
- freebn(tmp);
- }
- /* outx = (x + z)^2 * (x - z)^2 */
- outx = modmul(xpz, xmz, a->curve->p);
- /* outz = 4xz * ((x - z)^2 + ((A + 2) / 4)*4xz) */
- {
- Bignum _4xz, tmp, tmp2, tmp3;
- tmp = bignum_from_long(2);
- tmp2 = ecf_add(a->curve->m.a, tmp, a->curve);
- freebn(tmp);
- _4xz = modsub(xpz, xmz, a->curve->p);
- freebn(xpz);
- tmp = modmul(tmp2, _4xz, a->curve->p);
- freebn(tmp2);
- tmp2 = bignum_from_long(4);
- tmp3 = modinv(tmp2, a->curve->p);
- freebn(tmp2);
- if (!tmp3) {
- freebn(tmp);
- freebn(_4xz);
- freebn(outx);
- freebn(xmz);
- return NULL;
- }
- tmp2 = modmul(tmp, tmp3, a->curve->p);
- freebn(tmp);
- freebn(tmp3);
- tmp = ecf_add(xmz, tmp2, a->curve);
- freebn(xmz);
- freebn(tmp2);
- outz = modmul(_4xz, tmp, a->curve->p);
- freebn(_4xz);
- freebn(tmp);
- }
- return ec_point_new(a->curve, outx, NULL, outz, 0);
- }
- /* Forward declaration for Edwards curve doubling */
- static struct ec_point *ecp_add(const struct ec_point *a,
- const struct ec_point *b,
- const int aminus3);
- static struct ec_point *ecp_double(const struct ec_point *a, const int aminus3)
- {
- if (a->infinity)
- {
- /* Identity */
- return ec_point_new(a->curve, NULL, NULL, NULL, 1);
- }
- if (a->curve->type == EC_EDWARDS)
- {
- return ecp_add(a, a, aminus3);
- }
- else if (a->curve->type == EC_WEIERSTRASS)
- {
- return ecp_doublew(a, aminus3);
- }
- else
- {
- return ecp_doublem(a);
- }
- }
- static struct ec_point *ecp_addw(const struct ec_point *a,
- const struct ec_point *b,
- const int aminus3)
- {
- Bignum U1, U2, S1, S2, outx, outy, outz;
- /* U1 = X1*Z2^2 */
- /* S1 = Y1*Z2^3 */
- if (b->z) {
- Bignum Z2, Z3;
- Z2 = ecf_square(b->z, a->curve);
- U1 = modmul(a->x, Z2, a->curve->p);
- Z3 = modmul(Z2, b->z, a->curve->p);
- freebn(Z2);
- S1 = modmul(a->y, Z3, a->curve->p);
- freebn(Z3);
- } else {
- U1 = copybn(a->x);
- S1 = copybn(a->y);
- }
- /* U2 = X2*Z1^2 */
- /* S2 = Y2*Z1^3 */
- if (a->z) {
- Bignum Z2, Z3;
- Z2 = ecf_square(a->z, b->curve);
- U2 = modmul(b->x, Z2, b->curve->p);
- Z3 = modmul(Z2, a->z, b->curve->p);
- freebn(Z2);
- S2 = modmul(b->y, Z3, b->curve->p);
- freebn(Z3);
- } else {
- U2 = copybn(b->x);
- S2 = copybn(b->y);
- }
- /* Check if multiplying by self */
- if (bignum_cmp(U1, U2) == 0)
- {
- freebn(U1);
- freebn(U2);
- if (bignum_cmp(S1, S2) == 0)
- {
- freebn(S1);
- freebn(S2);
- return ecp_double(a, aminus3);
- }
- else
- {
- freebn(S1);
- freebn(S2);
- /* Infinity */
- return ec_point_new(a->curve, NULL, NULL, NULL, 1);
- }
- }
- {
- Bignum H, R, UH2, H3;
- /* H = U2 - U1 */
- H = modsub(U2, U1, a->curve->p);
- freebn(U2);
- /* R = S2 - S1 */
- R = modsub(S2, S1, a->curve->p);
- freebn(S2);
- /* X3 = R^2 - H^3 - 2*U1*H^2 */
- {
- Bignum R2, H2, _2UH2, first;
- H2 = ecf_square(H, a->curve);
- UH2 = modmul(U1, H2, a->curve->p);
- freebn(U1);
- H3 = modmul(H2, H, a->curve->p);
- freebn(H2);
- R2 = ecf_square(R, a->curve);
- _2UH2 = ecf_double(UH2, a->curve);
- first = modsub(R2, H3, a->curve->p);
- freebn(R2);
- outx = modsub(first, _2UH2, a->curve->p);
- freebn(first);
- freebn(_2UH2);
- }
- /* Y3 = R*(U1*H^2 - X3) - S1*H^3 */
- {
- Bignum RUH2mX, UH2mX, SH3;
- UH2mX = modsub(UH2, outx, a->curve->p);
- freebn(UH2);
- RUH2mX = modmul(R, UH2mX, a->curve->p);
- freebn(UH2mX);
- freebn(R);
- SH3 = modmul(S1, H3, a->curve->p);
- freebn(S1);
- freebn(H3);
- outy = modsub(RUH2mX, SH3, a->curve->p);
- freebn(RUH2mX);
- freebn(SH3);
- }
- /* Z3 = H*Z1*Z2 */
- if (a->z && b->z) {
- Bignum ZZ;
- ZZ = modmul(a->z, b->z, a->curve->p);
- outz = modmul(H, ZZ, a->curve->p);
- freebn(H);
- freebn(ZZ);
- } else if (a->z) {
- outz = modmul(H, a->z, a->curve->p);
- freebn(H);
- } else if (b->z) {
- outz = modmul(H, b->z, a->curve->p);
- freebn(H);
- } else {
- outz = H;
- }
- }
- return ec_point_new(a->curve, outx, outy, outz, 0);
- }
- static struct ec_point *ecp_addm(const struct ec_point *a,
- const struct ec_point *b,
- const struct ec_point *base)
- {
- Bignum outx, outz, az, bz;
- az = a->z;
- if (!az) {
- az = One;
- }
- bz = b->z;
- if (!bz) {
- bz = One;
- }
- /* a-b is maintained at 1 due to Montgomery ladder implementation */
- /* Xa+b = Za-b * ((Xa - Za)*(Xb + Zb) + (Xa + Za)*(Xb - Zb))^2 */
- /* Za+b = Xa-b * ((Xa - Za)*(Xb + Zb) - (Xa + Za)*(Xb - Zb))^2 */
- {
- Bignum tmp, tmp2, tmp3, tmp4;
- /* (Xa + Za) * (Xb - Zb) */
- tmp = ecf_add(a->x, az, a->curve);
- tmp2 = modsub(b->x, bz, a->curve->p);
- tmp3 = modmul(tmp, tmp2, a->curve->p);
- freebn(tmp);
- freebn(tmp2);
- /* (Xa - Za) * (Xb + Zb) */
- tmp = modsub(a->x, az, a->curve->p);
- tmp2 = ecf_add(b->x, bz, a->curve);
- tmp4 = modmul(tmp, tmp2, a->curve->p);
- freebn(tmp);
- freebn(tmp2);
- tmp = ecf_add(tmp3, tmp4, a->curve);
- outx = ecf_square(tmp, a->curve);
- freebn(tmp);
- tmp = modsub(tmp3, tmp4, a->curve->p);
- freebn(tmp3);
- freebn(tmp4);
- tmp2 = ecf_square(tmp, a->curve);
- freebn(tmp);
- outz = modmul(base->x, tmp2, a->curve->p);
- freebn(tmp2);
- }
- return ec_point_new(a->curve, outx, NULL, outz, 0);
- }
- static struct ec_point *ecp_adde(const struct ec_point *a,
- const struct ec_point *b)
- {
- Bignum outx, outy, dmul;
- /* outx = (a->x * b->y + b->x * a->y) /
- * (1 + a->curve->e.d * a->x * b->x * a->y * b->y) */
- {
- Bignum tmp, tmp2, tmp3, tmp4;
- tmp = modmul(a->x, b->y, a->curve->p);
- tmp2 = modmul(b->x, a->y, a->curve->p);
- tmp3 = ecf_add(tmp, tmp2, a->curve);
- tmp4 = modmul(tmp, tmp2, a->curve->p);
- freebn(tmp);
- freebn(tmp2);
- dmul = modmul(a->curve->e.d, tmp4, a->curve->p);
- freebn(tmp4);
- tmp = ecf_add(One, dmul, a->curve);
- tmp2 = modinv(tmp, a->curve->p);
- freebn(tmp);
- if (!tmp2)
- {
- freebn(tmp3);
- freebn(dmul);
- return NULL;
- }
- outx = modmul(tmp3, tmp2, a->curve->p);
- freebn(tmp3);
- freebn(tmp2);
- }
- /* outy = (a->y * b->y + a->x * b->x) /
- * (1 - a->curve->e.d * a->x * b->x * a->y * b->y) */
- {
- Bignum tmp, tmp2, tmp3, tmp4;
- tmp = modsub(One, dmul, a->curve->p);
- freebn(dmul);
- tmp2 = modinv(tmp, a->curve->p);
- freebn(tmp);
- if (!tmp2)
- {
- freebn(outx);
- return NULL;
- }
- tmp = modmul(a->y, b->y, a->curve->p);
- tmp3 = modmul(a->x, b->x, a->curve->p);
- tmp4 = ecf_add(tmp, tmp3, a->curve);
- freebn(tmp);
- freebn(tmp3);
- outy = modmul(tmp4, tmp2, a->curve->p);
- freebn(tmp4);
- freebn(tmp2);
- }
- return ec_point_new(a->curve, outx, outy, NULL, 0);
- }
- static struct ec_point *ecp_add(const struct ec_point *a,
- const struct ec_point *b,
- const int aminus3)
- {
- if (a->curve != b->curve) {
- return NULL;
- }
- /* Check if multiplying by infinity */
- if (a->infinity) return ec_point_copy(b);
- if (b->infinity) return ec_point_copy(a);
- if (a->curve->type == EC_EDWARDS)
- {
- return ecp_adde(a, b);
- }
- if (a->curve->type == EC_WEIERSTRASS)
- {
- return ecp_addw(a, b, aminus3);
- }
- return NULL;
- }
- static struct ec_point *ecp_mul_(const struct ec_point *a, const Bignum b, int aminus3)
- {
- struct ec_point *A, *ret;
- int bits, i;
- A = ec_point_copy(a);
- ret = ec_point_new(a->curve, NULL, NULL, NULL, 1);
- bits = bignum_bitcount(b);
- for (i = 0; i < bits; ++i)
- {
- if (bignum_bit(b, i))
- {
- struct ec_point *tmp = ecp_add(ret, A, aminus3);
- ec_point_free(ret);
- ret = tmp;
- }
- if (i+1 != bits)
- {
- struct ec_point *tmp = ecp_double(A, aminus3);
- ec_point_free(A);
- A = tmp;
- }
- }
- ec_point_free(A);
- return ret;
- }
- static struct ec_point *ecp_mulw(const struct ec_point *a, const Bignum b)
- {
- struct ec_point *ret = ecp_mul_(a, b, ec_aminus3(a->curve));
- if (!ecp_normalise(ret)) {
- ec_point_free(ret);
- return NULL;
- }
- return ret;
- }
- static struct ec_point *ecp_mule(const struct ec_point *a, const Bignum b)
- {
- int i;
- struct ec_point *ret;
- ret = ec_point_new(a->curve, NULL, NULL, NULL, 1);
- for (i = bignum_bitcount(b); i >= 0 && ret; --i)
- {
- {
- struct ec_point *tmp = ecp_double(ret, 0);
- ec_point_free(ret);
- ret = tmp;
- }
- if (ret && bignum_bit(b, i))
- {
- struct ec_point *tmp = ecp_add(ret, a, 0);
- ec_point_free(ret);
- ret = tmp;
- }
- }
- return ret;
- }
- static struct ec_point *ecp_mulm(const struct ec_point *p, const Bignum n)
- {
- struct ec_point *P1, *P2;
- int bits, i;
- /* P1 <- P and P2 <- [2]P */
- P2 = ecp_double(p, 0);
- P1 = ec_point_copy(p);
- /* for i = bits − 2 down to 0 */
- bits = bignum_bitcount(n);
- for (i = bits - 2; i >= 0; --i)
- {
- if (!bignum_bit(n, i))
- {
- /* P2 <- P1 + P2 */
- struct ec_point *tmp = ecp_addm(P1, P2, p);
- ec_point_free(P2);
- P2 = tmp;
- /* P1 <- [2]P1 */
- tmp = ecp_double(P1, 0);
- ec_point_free(P1);
- P1 = tmp;
- }
- else
- {
- /* P1 <- P1 + P2 */
- struct ec_point *tmp = ecp_addm(P1, P2, p);
- ec_point_free(P1);
- P1 = tmp;
- /* P2 <- [2]P2 */
- tmp = ecp_double(P2, 0);
- ec_point_free(P2);
- P2 = tmp;
- }
- }
- ec_point_free(P2);
- if (!ecp_normalise(P1)) {
- ec_point_free(P1);
- return NULL;
- }
- return P1;
- }
- /* Not static because it is used by sshecdsag.c to generate a new key */
- struct ec_point *ecp_mul(const struct ec_point *a, const Bignum b)
- {
- if (a->curve->type == EC_WEIERSTRASS) {
- return ecp_mulw(a, b);
- } else if (a->curve->type == EC_EDWARDS) {
- return ecp_mule(a, b);
- } else {
- return ecp_mulm(a, b);
- }
- }
- static struct ec_point *ecp_summul(const Bignum a, const Bignum b,
- const struct ec_point *point)
- {
- struct ec_point *aG, *bP, *ret;
- int aminus3;
- if (point->curve->type != EC_WEIERSTRASS) {
- return NULL;
- }
- aminus3 = ec_aminus3(point->curve);
- aG = ecp_mul_(&point->curve->w.G, a, aminus3);
- if (!aG) return NULL;
- bP = ecp_mul_(point, b, aminus3);
- if (!bP) {
- ec_point_free(aG);
- return NULL;
- }
- ret = ecp_add(aG, bP, aminus3);
- ec_point_free(aG);
- ec_point_free(bP);
- if (!ecp_normalise(ret)) {
- ec_point_free(ret);
- return NULL;
- }
- return ret;
- }
- static Bignum *ecp_edx(const struct ec_curve *curve, const Bignum y)
- {
- /* Get the x value on the given Edwards curve for a given y */
- Bignum x, xx;
- /* xx = (y^2 - 1) / (d * y^2 + 1) */
- {
- Bignum tmp, tmp2, tmp3;
- tmp = ecf_square(y, curve);
- tmp2 = modmul(curve->e.d, tmp, curve->p);
- tmp3 = ecf_add(tmp2, One, curve);
- freebn(tmp2);
- tmp2 = modinv(tmp3, curve->p);
- freebn(tmp3);
- if (!tmp2) {
- freebn(tmp);
- return NULL;
- }
- tmp3 = modsub(tmp, One, curve->p);
- freebn(tmp);
- xx = modmul(tmp3, tmp2, curve->p);
- freebn(tmp3);
- freebn(tmp2);
- }
- /* x = xx^((p + 3) / 8) */
- {
- Bignum tmp, tmp2;
- tmp = bignum_add_long(curve->p, 3);
- tmp2 = bignum_rshift(tmp, 3);
- freebn(tmp);
- x = modpow(xx, tmp2, curve->p);
- freebn(tmp2);
- }
- /* if x^2 - xx != 0 then x = x*(2^((p - 1) / 4)) */
- {
- Bignum tmp, tmp2;
- tmp = ecf_square(x, curve);
- tmp2 = modsub(tmp, xx, curve->p);
- freebn(tmp);
- freebn(xx);
- if (bignum_cmp(tmp2, Zero)) {
- Bignum tmp3;
- freebn(tmp2);
- tmp = modsub(curve->p, One, curve->p);
- tmp2 = bignum_rshift(tmp, 2);
- freebn(tmp);
- tmp = bignum_from_long(2);
- tmp3 = modpow(tmp, tmp2, curve->p);
- freebn(tmp);
- freebn(tmp2);
- tmp = modmul(x, tmp3, curve->p);
- freebn(x);
- freebn(tmp3);
- x = tmp;
- } else {
- freebn(tmp2);
- }
- }
- /* if x % 2 != 0 then x = p - x */
- if (bignum_bit(x, 0)) {
- Bignum tmp = modsub(curve->p, x, curve->p);
- freebn(x);
- x = tmp;
- }
- return x;
- }
- /* ----------------------------------------------------------------------
- * Public point from private
- */
- struct ec_point *ec_public(const Bignum privateKey, const struct ec_curve *curve)
- {
- if (curve->type == EC_WEIERSTRASS) {
- return ecp_mul(&curve->w.G, privateKey);
- } else if (curve->type == EC_EDWARDS) {
- /* hash = H(sk) (where hash creates 2 * fieldBits)
- * b = fieldBits
- * a = 2^(b-2) + SUM(2^i * h_i) for i = 2 -> b-2
- * publicKey = aB */
- struct ec_point *ret;
- unsigned char hash[512/8];
- Bignum a;
- int i, keylen;
- SHA512_State s;
- SHA512_Init(&s);
- keylen = curve->fieldBits / 8;
- for (i = 0; i < keylen; ++i) {
- unsigned char b = bignum_byte(privateKey, i);
- SHA512_Bytes(&s, &b, 1);
- }
- SHA512_Final(&s, hash);
- /* The second part is simply turning the hash into a Bignum,
- * however the 2^(b-2) bit *must* be set, and the bottom 3
- * bits *must* not be */
- hash[0] &= 0xf8; /* Unset bottom 3 bits (if set) */
- hash[31] &= 0x7f; /* Unset above (b-2) */
- hash[31] |= 0x40; /* Set 2^(b-2) */
- /* Chop off the top part and convert to int */
- a = bignum_from_bytes_le(hash, 32);
- ret = ecp_mul(&curve->e.B, a);
- freebn(a);
- return ret;
- } else {
- return NULL;
- }
- }
- /* ----------------------------------------------------------------------
- * Basic sign and verify routines
- */
- static int _ecdsa_verify(const struct ec_point *publicKey,
- const unsigned char *data, const int dataLen,
- const Bignum r, const Bignum s)
- {
- int z_bits, n_bits;
- Bignum z;
- int valid = 0;
- if (publicKey->curve->type != EC_WEIERSTRASS) {
- return 0;
- }
- /* Sanity checks */
- if (bignum_cmp(r, Zero) == 0 || bignum_cmp(r, publicKey->curve->w.n) >= 0
- || bignum_cmp(s, Zero) == 0 || bignum_cmp(s, publicKey->curve->w.n) >= 0)
- {
- return 0;
- }
- /* z = left most bitlen(curve->n) of data */
- z = bignum_from_bytes(data, dataLen);
- n_bits = bignum_bitcount(publicKey->curve->w.n);
- z_bits = bignum_bitcount(z);
- if (z_bits > n_bits)
- {
- Bignum tmp = bignum_rshift(z, z_bits - n_bits);
- freebn(z);
- z = tmp;
- }
- /* Ensure z in range of n */
- {
- Bignum tmp = bigmod(z, publicKey->curve->w.n);
- freebn(z);
- z = tmp;
- }
- /* Calculate signature */
- {
- Bignum w, x, u1, u2;
- struct ec_point *tmp;
- w = modinv(s, publicKey->curve->w.n);
- if (!w) {
- freebn(z);
- return 0;
- }
- u1 = modmul(z, w, publicKey->curve->w.n);
- u2 = modmul(r, w, publicKey->curve->w.n);
- freebn(w);
- tmp = ecp_summul(u1, u2, publicKey);
- freebn(u1);
- freebn(u2);
- if (!tmp) {
- freebn(z);
- return 0;
- }
- x = bigmod(tmp->x, publicKey->curve->w.n);
- ec_point_free(tmp);
- valid = (bignum_cmp(r, x) == 0) ? 1 : 0;
- freebn(x);
- }
- freebn(z);
- return valid;
- }
- static void _ecdsa_sign(const Bignum privateKey, const struct ec_curve *curve,
- const unsigned char *data, const int dataLen,
- Bignum *r, Bignum *s)
- {
- unsigned char digest[20];
- int z_bits, n_bits;
- Bignum z, k;
- struct ec_point *kG;
- *r = NULL;
- *s = NULL;
- if (curve->type != EC_WEIERSTRASS) {
- return;
- }
- /* z = left most bitlen(curve->n) of data */
- z = bignum_from_bytes(data, dataLen);
- n_bits = bignum_bitcount(curve->w.n);
- z_bits = bignum_bitcount(z);
- if (z_bits > n_bits)
- {
- Bignum tmp;
- tmp = bignum_rshift(z, z_bits - n_bits);
- freebn(z);
- z = tmp;
- }
- /* Generate k between 1 and curve->n, using the same deterministic
- * k generation system we use for conventional DSA. */
- SHA_Simple(data, dataLen, digest);
- k = dss_gen_k("ECDSA deterministic k generator", curve->w.n, privateKey,
- digest, sizeof(digest));
- kG = ecp_mul(&curve->w.G, k);
- if (!kG) {
- freebn(z);
- freebn(k);
- return;
- }
- /* r = kG.x mod n */
- *r = bigmod(kG->x, curve->w.n);
- ec_point_free(kG);
- /* s = (z + r * priv)/k mod n */
- {
- Bignum rPriv, zMod, first, firstMod, kInv;
- rPriv = modmul(*r, privateKey, curve->w.n);
- zMod = bigmod(z, curve->w.n);
- freebn(z);
- first = bigadd(rPriv, zMod);
- freebn(rPriv);
- freebn(zMod);
- firstMod = bigmod(first, curve->w.n);
- freebn(first);
- kInv = modinv(k, curve->w.n);
- freebn(k);
- if (!kInv) {
- freebn(firstMod);
- freebn(*r);
- return;
- }
- *s = modmul(firstMod, kInv, curve->w.n);
- freebn(firstMod);
- freebn(kInv);
- }
- }
- /* ----------------------------------------------------------------------
- * Misc functions
- */
- static void getstring(const char **data, int *datalen,
- const char **p, int *length)
- {
- *p = NULL;
- if (*datalen < 4)
- return;
- *length = toint(GET_32BIT(*data));
- if (*length < 0)
- return;
- *datalen -= 4;
- *data += 4;
- if (*datalen < *length)
- return;
- *p = *data;
- *data += *length;
- *datalen -= *length;
- }
- static Bignum getmp(const char **data, int *datalen)
- {
- const char *p;
- int length;
- getstring(data, datalen, &p, &length);
- if (!p)
- return NULL;
- if (p[0] & 0x80)
- return NULL; /* negative mp */
- return bignum_from_bytes((unsigned char *)p, length);
- }
- static Bignum getmp_le(const char **data, int *datalen)
- {
- const char *p;
- int length;
- getstring(data, datalen, &p, &length);
- if (!p)
- return NULL;
- return bignum_from_bytes_le((const unsigned char *)p, length);
- }
- static int decodepoint_ed(const char *p, int length, struct ec_point *point)
- {
- /* Got some conversion to do, first read in the y co-ord */
- int negative;
- point->y = bignum_from_bytes_le((const unsigned char*)p, length);
- if ((unsigned)bignum_bitcount(point->y) > point->curve->fieldBits) {
- freebn(point->y);
- point->y = NULL;
- return 0;
- }
- /* Read x bit and then reset it */
- negative = bignum_bit(point->y, point->curve->fieldBits - 1);
- bignum_set_bit(point->y, point->curve->fieldBits - 1, 0);
- bn_restore_invariant(point->y);
- /* Get the x from the y */
- point->x = ecp_edx(point->curve, point->y);
- if (!point->x) {
- freebn(point->y);
- point->y = NULL;
- return 0;
- }
- if (negative) {
- Bignum tmp = modsub(point->curve->p, point->x, point->curve->p);
- freebn(point->x);
- point->x = tmp;
- }
- /* Verify the point is on the curve */
- if (!ec_point_verify(point)) {
- freebn(point->x);
- point->x = NULL;
- freebn(point->y);
- point->y = NULL;
- return 0;
- }
- return 1;
- }
- static int decodepoint(const char *p, int length, struct ec_point *point)
- {
- if (point->curve->type == EC_EDWARDS) {
- return decodepoint_ed(p, length, point);
- }
- if (length < 1 || p[0] != 0x04) /* Only support uncompressed point */
- return 0;
- /* Skip compression flag */
- ++p;
- --length;
- /* The two values must be equal length */
- if (length % 2 != 0) {
- point->x = NULL;
- point->y = NULL;
- point->z = NULL;
- return 0;
- }
- length = length / 2;
- point->x = bignum_from_bytes((const unsigned char *)p, length);
- p += length;
- point->y = bignum_from_bytes((const unsigned char *)p, length);
- point->z = NULL;
- /* Verify the point is on the curve */
- if (!ec_point_verify(point)) {
- freebn(point->x);
- point->x = NULL;
- freebn(point->y);
- point->y = NULL;
- return 0;
- }
- return 1;
- }
- static int getmppoint(const char **data, int *datalen, struct ec_point *point)
- {
- const char *p;
- int length;
- getstring(data, datalen, &p, &length);
- if (!p) return 0;
- return decodepoint(p, length, point);
- }
- /* ----------------------------------------------------------------------
- * Exposed ECDSA interface
- */
- struct ecsign_extra {
- struct ec_curve *(*curve)(void);
- const struct ssh_hash *hash;
- /* These fields are used by the OpenSSH PEM format importer/exporter */
- const unsigned char *oid;
- int oidlen;
- };
- static void ecdsa_freekey(void *key)
- {
- struct ec_key *ec = (struct ec_key *) key;
- if (!ec) return;
- if (ec->publicKey.x)
- freebn(ec->publicKey.x);
- if (ec->publicKey.y)
- freebn(ec->publicKey.y);
- if (ec->publicKey.z)
- freebn(ec->publicKey.z);
- if (ec->privateKey)
- freebn(ec->privateKey);
- sfree(ec);
- }
- static void *ecdsa_newkey(const struct ssh_signkey *self,
- const char *data, int len)
- {
- const struct ecsign_extra *extra =
- (const struct ecsign_extra *)self->extra;
- const char *p;
- int slen;
- struct ec_key *ec;
- struct ec_curve *curve;
- getstring(&data, &len, &p, &slen);
- if (!p) {
- return NULL;
- }
- curve = extra->curve();
- assert(curve->type == EC_WEIERSTRASS || curve->type == EC_EDWARDS);
- /* Curve name is duplicated for Weierstrass form */
- if (curve->type == EC_WEIERSTRASS) {
- getstring(&data, &len, &p, &slen);
- if (!p) return NULL;
- if (!match_ssh_id(slen, p, curve->name)) return NULL;
- }
- ec = snew(struct ec_key);
- ec->signalg = self;
- ec->publicKey.curve = curve;
- ec->publicKey.infinity = 0;
- ec->publicKey.x = NULL;
- ec->publicKey.y = NULL;
- ec->publicKey.z = NULL;
- ec->privateKey = NULL;
- if (!getmppoint(&data, &len, &ec->publicKey)) {
- ecdsa_freekey(ec);
- return NULL;
- }
- if (!ec->publicKey.x || !ec->publicKey.y ||
- bignum_cmp(ec->publicKey.x, curve->p) >= 0 ||
- bignum_cmp(ec->publicKey.y, curve->p) >= 0)
- {
- ecdsa_freekey(ec);
- ec = NULL;
- }
- return ec;
- }
- static char *ecdsa_fmtkey(void *key)
- {
- struct ec_key *ec = (struct ec_key *) key;
- char *p;
- int len, i, pos, nibbles;
- static const char hex[] = "0123456789abcdef";
- if (!ec->publicKey.x || !ec->publicKey.y || !ec->publicKey.curve)
- return NULL;
- len = 4 + 2 + 1; /* 2 x "0x", punctuation, \0 */
- if (ec->publicKey.curve->name)
- len += strlen(ec->publicKey.curve->name); /* Curve name */
- len += 4 * (bignum_bitcount(ec->publicKey.x) + 15) / 16;
- len += 4 * (bignum_bitcount(ec->publicKey.y) + 15) / 16;
- p = snewn(len, char);
- pos = 0;
- if (ec->publicKey.curve->name)
- pos += sprintf(p + pos, "%s,", ec->publicKey.curve->name);
- pos += sprintf(p + pos, "0x");
- nibbles = (3 + bignum_bitcount(ec->publicKey.x)) / 4;
- if (nibbles < 1)
- nibbles = 1;
- for (i = nibbles; i--;) {
- p[pos++] =
- hex[(bignum_byte(ec->publicKey.x, i / 2) >> (4 * (i % 2))) & 0xF];
- }
- pos += sprintf(p + pos, ",0x");
- nibbles = (3 + bignum_bitcount(ec->publicKey.y)) / 4;
- if (nibbles < 1)
- nibbles = 1;
- for (i = nibbles; i--;) {
- p[pos++] =
- hex[(bignum_byte(ec->publicKey.y, i / 2) >> (4 * (i % 2))) & 0xF];
- }
- p[pos] = '\0';
- return p;
- }
- static unsigned char *ecdsa_public_blob(void *key, int *len)
- {
- struct ec_key *ec = (struct ec_key *) key;
- int pointlen, bloblen, fullnamelen, namelen;
- int i;
- unsigned char *blob, *p;
- fullnamelen = strlen(ec->signalg->name);
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- /* Edwards compressed form "ssh-ed25519" point y[:-1] + x[0:1] */
- pointlen = ec->publicKey.curve->fieldBits / 8;
- /* Can't handle this in our loop */
- if (pointlen < 2) return NULL;
- bloblen = 4 + fullnamelen + 4 + pointlen;
- blob = snewn(bloblen, unsigned char);
- p = blob;
- PUT_32BIT(p, fullnamelen);
- p += 4;
- memcpy(p, ec->signalg->name, fullnamelen);
- p += fullnamelen;
- PUT_32BIT(p, pointlen);
- p += 4;
- /* Unset last bit of y and set first bit of x in its place */
- for (i = 0; i < pointlen - 1; ++i) {
- *p++ = bignum_byte(ec->publicKey.y, i);
- }
- /* Unset last bit of y and set first bit of x in its place */
- *p = bignum_byte(ec->publicKey.y, i) & 0x7f;
- *p++ |= bignum_bit(ec->publicKey.x, 0) << 7;
- } else if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
- assert(ec->publicKey.curve->name);
- namelen = strlen(ec->publicKey.curve->name);
- pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
- /*
- * string "ecdsa-sha2-<name>", string "<name>", 0x04 point x, y.
- */
- bloblen = 4 + fullnamelen + 4 + namelen + 4 + 1 + (pointlen * 2);
- blob = snewn(bloblen, unsigned char);
- p = blob;
- PUT_32BIT(p, fullnamelen);
- p += 4;
- memcpy(p, ec->signalg->name, fullnamelen);
- p += fullnamelen;
- PUT_32BIT(p, namelen);
- p += 4;
- memcpy(p, ec->publicKey.curve->name, namelen);
- p += namelen;
- PUT_32BIT(p, (2 * pointlen) + 1);
- p += 4;
- *p++ = 0x04;
- for (i = pointlen; i--;) {
- *p++ = bignum_byte(ec->publicKey.x, i);
- }
- for (i = pointlen; i--;) {
- *p++ = bignum_byte(ec->publicKey.y, i);
- }
- } else {
- return NULL;
- }
- assert(p == blob + bloblen);
- *len = bloblen;
- return blob;
- }
- static unsigned char *ecdsa_private_blob(void *key, int *len)
- {
- struct ec_key *ec = (struct ec_key *) key;
- int keylen, bloblen;
- int i;
- unsigned char *blob, *p;
- if (!ec->privateKey) return NULL;
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- /* Unsigned */
- keylen = (bignum_bitcount(ec->privateKey) + 7) / 8;
- } else {
- /* Signed */
- keylen = (bignum_bitcount(ec->privateKey) + 8) / 8;
- }
- /*
- * mpint privateKey. Total 4 + keylen.
- */
- bloblen = 4 + keylen;
- blob = snewn(bloblen, unsigned char);
- p = blob;
- PUT_32BIT(p, keylen);
- p += 4;
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- /* Little endian */
- for (i = 0; i < keylen; ++i)
- *p++ = bignum_byte(ec->privateKey, i);
- } else {
- for (i = keylen; i--;)
- *p++ = bignum_byte(ec->privateKey, i);
- }
- assert(p == blob + bloblen);
- *len = bloblen;
- return blob;
- }
- static void *ecdsa_createkey(const struct ssh_signkey *self,
- const unsigned char *pub_blob, int pub_len,
- const unsigned char *priv_blob, int priv_len)
- {
- struct ec_key *ec;
- struct ec_point *publicKey;
- const char *pb = (const char *) priv_blob;
- ec = (struct ec_key*)ecdsa_newkey(self, (const char *) pub_blob, pub_len);
- if (!ec) {
- return NULL;
- }
- if (ec->publicKey.curve->type != EC_WEIERSTRASS
- && ec->publicKey.curve->type != EC_EDWARDS) {
- ecdsa_freekey(ec);
- return NULL;
- }
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- ec->privateKey = getmp_le(&pb, &priv_len);
- } else {
- ec->privateKey = getmp(&pb, &priv_len);
- }
- if (!ec->privateKey) {
- ecdsa_freekey(ec);
- return NULL;
- }
- /* Check that private key generates public key */
- publicKey = ec_public(ec->privateKey, ec->publicKey.curve);
- if (!publicKey ||
- bignum_cmp(publicKey->x, ec->publicKey.x) ||
- bignum_cmp(publicKey->y, ec->publicKey.y))
- {
- ecdsa_freekey(ec);
- ec = NULL;
- }
- ec_point_free(publicKey);
- return ec;
- }
- static void *ed25519_openssh_createkey(const struct ssh_signkey *self,
- const unsigned char **blob, int *len)
- {
- struct ec_key *ec;
- struct ec_point *publicKey;
- const char *p, *q;
- int plen, qlen;
- getstring((const char**)blob, len, &p, &plen);
- if (!p)
- {
- return NULL;
- }
- ec = snew(struct ec_key);
- ec->signalg = self;
- ec->publicKey.curve = ec_ed25519();
- ec->publicKey.infinity = 0;
- ec->privateKey = NULL;
- ec->publicKey.x = NULL;
- ec->publicKey.z = NULL;
- ec->publicKey.y = NULL;
- if (!decodepoint_ed(p, plen, &ec->publicKey))
- {
- ecdsa_freekey(ec);
- return NULL;
- }
- getstring((const char**)blob, len, &q, &qlen);
- if (!q)
- return NULL;
- if (qlen != 64)
- return NULL;
- ec->privateKey = bignum_from_bytes_le((const unsigned char *)q, 32);
- /* Check that private key generates public key */
- publicKey = ec_public(ec->privateKey, ec->publicKey.curve);
- if (!publicKey ||
- bignum_cmp(publicKey->x, ec->publicKey.x) ||
- bignum_cmp(publicKey->y, ec->publicKey.y))
- {
- ecdsa_freekey(ec);
- ec = NULL;
- }
- ec_point_free(publicKey);
- /* The OpenSSH format for ed25519 private keys also for some
- * reason encodes an extra copy of the public key in the second
- * half of the secret-key string. Check that that's present and
- * correct as well, otherwise the key we think we've imported
- * won't behave identically to the way OpenSSH would have treated
- * it. */
- if (plen != 32 || 0 != memcmp(q + 32, p, 32)) {
- ecdsa_freekey(ec);
- return NULL;
- }
- return ec;
- }
- static int ed25519_openssh_fmtkey(void *key, unsigned char *blob, int len)
- {
- struct ec_key *ec = (struct ec_key *) key;
- int pointlen;
- int keylen;
- int bloblen;
- int i;
- if (ec->publicKey.curve->type != EC_EDWARDS) {
- return 0;
- }
- pointlen = (bignum_bitcount(ec->publicKey.y) + 7) / 8;
- keylen = (bignum_bitcount(ec->privateKey) + 7) / 8;
- bloblen = 4 + pointlen + 4 + keylen + pointlen;
- if (bloblen > len)
- return bloblen;
- /* Encode the public point */
- PUT_32BIT(blob, pointlen);
- blob += 4;
- for (i = 0; i < pointlen - 1; ++i) {
- *blob++ = bignum_byte(ec->publicKey.y, i);
- }
- /* Unset last bit of y and set first bit of x in its place */
- *blob = bignum_byte(ec->publicKey.y, i) & 0x7f;
- *blob++ |= bignum_bit(ec->publicKey.x, 0) << 7;
- PUT_32BIT(blob, keylen + pointlen);
- blob += 4;
- for (i = 0; i < keylen; ++i) {
- *blob++ = bignum_byte(ec->privateKey, i);
- }
- /* Now encode an extra copy of the public point as the second half
- * of the private key string, as the OpenSSH format for some
- * reason requires */
- for (i = 0; i < pointlen - 1; ++i) {
- *blob++ = bignum_byte(ec->publicKey.y, i);
- }
- /* Unset last bit of y and set first bit of x in its place */
- *blob = bignum_byte(ec->publicKey.y, i) & 0x7f;
- *blob++ |= bignum_bit(ec->publicKey.x, 0) << 7;
- return bloblen;
- }
- static void *ecdsa_openssh_createkey(const struct ssh_signkey *self,
- const unsigned char **blob, int *len)
- {
- const struct ecsign_extra *extra =
- (const struct ecsign_extra *)self->extra;
- const char **b = (const char **) blob;
- const char *p;
- int slen;
- struct ec_key *ec;
- struct ec_curve *curve;
- struct ec_point *publicKey;
- getstring(b, len, &p, &slen);
- if (!p) {
- return NULL;
- }
- curve = extra->curve();
- assert(curve->type == EC_WEIERSTRASS);
- ec = snew(struct ec_key);
- ec->signalg = self;
- ec->publicKey.curve = curve;
- ec->publicKey.infinity = 0;
- ec->publicKey.x = NULL;
- ec->publicKey.y = NULL;
- ec->publicKey.z = NULL;
- if (!getmppoint(b, len, &ec->publicKey)) {
- ecdsa_freekey(ec);
- return NULL;
- }
- ec->privateKey = NULL;
- if (!ec->publicKey.x || !ec->publicKey.y ||
- bignum_cmp(ec->publicKey.x, curve->p) >= 0 ||
- bignum_cmp(ec->publicKey.y, curve->p) >= 0)
- {
- ecdsa_freekey(ec);
- return NULL;
- }
- ec->privateKey = getmp(b, len);
- if (ec->privateKey == NULL)
- {
- ecdsa_freekey(ec);
- return NULL;
- }
- /* Now check that the private key makes the public key */
- publicKey = ec_public(ec->privateKey, ec->publicKey.curve);
- if (!publicKey)
- {
- ecdsa_freekey(ec);
- return NULL;
- }
- if (bignum_cmp(ec->publicKey.x, publicKey->x) ||
- bignum_cmp(ec->publicKey.y, publicKey->y))
- {
- /* Private key doesn't make the public key on the given curve */
- ecdsa_freekey(ec);
- ec_point_free(publicKey);
- return NULL;
- }
- ec_point_free(publicKey);
- return ec;
- }
- static int ecdsa_openssh_fmtkey(void *key, unsigned char *blob, int len)
- {
- struct ec_key *ec = (struct ec_key *) key;
- int pointlen;
- int namelen;
- int bloblen;
- int i;
- if (ec->publicKey.curve->type != EC_WEIERSTRASS) {
- return 0;
- }
- pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
- namelen = strlen(ec->publicKey.curve->name);
- bloblen =
- 4 + namelen /* <LEN> nistpXXX */
- + 4 + 1 + (pointlen * 2) /* <LEN> 0x04 pX pY */
- + ssh2_bignum_length(ec->privateKey);
- if (bloblen > len)
- return bloblen;
- bloblen = 0;
- PUT_32BIT(blob+bloblen, namelen);
- bloblen += 4;
- memcpy(blob+bloblen, ec->publicKey.curve->name, namelen);
- bloblen += namelen;
- PUT_32BIT(blob+bloblen, 1 + (pointlen * 2));
- bloblen += 4;
- blob[bloblen++] = 0x04;
- for (i = pointlen; i--; )
- blob[bloblen++] = bignum_byte(ec->publicKey.x, i);
- for (i = pointlen; i--; )
- blob[bloblen++] = bignum_byte(ec->publicKey.y, i);
- pointlen = (bignum_bitcount(ec->privateKey) + 8) / 8;
- PUT_32BIT(blob+bloblen, pointlen);
- bloblen += 4;
- for (i = pointlen; i--; )
- blob[bloblen++] = bignum_byte(ec->privateKey, i);
- return bloblen;
- }
- static int ecdsa_pubkey_bits(const struct ssh_signkey *self,
- const void *blob, int len)
- {
- struct ec_key *ec;
- int ret;
- ec = (struct ec_key*)ecdsa_newkey(self, (const char *) blob, len);
- if (!ec)
- return -1;
- ret = ec->publicKey.curve->fieldBits;
- ecdsa_freekey(ec);
- return ret;
- }
- static int ecdsa_verifysig(void *key, const char *sig, int siglen,
- const char *data, int datalen)
- {
- struct ec_key *ec = (struct ec_key *) key;
- const struct ecsign_extra *extra =
- (const struct ecsign_extra *)ec->signalg->extra;
- const char *p;
- int slen;
- int digestLen;
- int ret;
- if (!ec->publicKey.x || !ec->publicKey.y || !ec->publicKey.curve)
- return 0;
- /* Check the signature starts with the algorithm name */
- getstring(&sig, &siglen, &p, &slen);
- if (!p) {
- return 0;
- }
- if (!match_ssh_id(slen, p, ec->signalg->name)) {
- return 0;
- }
- getstring(&sig, &siglen, &p, &slen);
- if (!p) return 0;
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- struct ec_point *r;
- Bignum s, h;
- /* Check that the signature is two times the length of a point */
- if (slen != (ec->publicKey.curve->fieldBits / 8) * 2) {
- return 0;
- }
- /* Check it's the 256 bit field so that SHA512 is the correct hash */
- if (ec->publicKey.curve->fieldBits != 256) {
- return 0;
- }
- /* Get the signature */
- r = ec_point_new(ec->publicKey.curve, NULL, NULL, NULL, 0);
- if (!r) {
- return 0;
- }
- if (!decodepoint(p, ec->publicKey.curve->fieldBits / 8, r)) {
- ec_point_free(r);
- return 0;
- }
- s = bignum_from_bytes_le((unsigned char*)p + (ec->publicKey.curve->fieldBits / 8),
- ec->publicKey.curve->fieldBits / 8);
- /* Get the hash of the encoded value of R + encoded value of pk + message */
- {
- int i, pointlen;
- unsigned char b;
- unsigned char digest[512 / 8];
- SHA512_State hs;
- SHA512_Init(&hs);
- /* Add encoded r (no need to encode it again, it was in the signature) */
- SHA512_Bytes(&hs, p, ec->publicKey.curve->fieldBits / 8);
- /* Encode pk and add it */
- pointlen = ec->publicKey.curve->fieldBits / 8;
- for (i = 0; i < pointlen - 1; ++i) {
- b = bignum_byte(ec->publicKey.y, i);
- SHA512_Bytes(&hs, &b, 1);
- }
- /* Unset last bit of y and set first bit of x in its place */
- b = bignum_byte(ec->publicKey.y, i) & 0x7f;
- b |= bignum_bit(ec->publicKey.x, 0) << 7;
- SHA512_Bytes(&hs, &b, 1);
- /* Add the message itself */
- SHA512_Bytes(&hs, data, datalen);
- /* Get the hash */
- SHA512_Final(&hs, digest);
- /* Convert to Bignum */
- h = bignum_from_bytes_le(digest, sizeof(digest));
- }
- /* Verify sB == r + h*publicKey */
- {
- struct ec_point *lhs, *rhs, *tmp;
- /* lhs = sB */
- lhs = ecp_mul(&ec->publicKey.curve->e.B, s);
- freebn(s);
- if (!lhs) {
- ec_point_free(r);
- freebn(h);
- return 0;
- }
- /* rhs = r + h*publicKey */
- tmp = ecp_mul(&ec->publicKey, h);
- freebn(h);
- if (!tmp) {
- ec_point_free(lhs);
- ec_point_free(r);
- return 0;
- }
- rhs = ecp_add(r, tmp, 0);
- ec_point_free(r);
- ec_point_free(tmp);
- if (!rhs) {
- ec_point_free(lhs);
- return 0;
- }
- /* Check the point is the same */
- ret = !bignum_cmp(lhs->x, rhs->x);
- if (ret) {
- ret = !bignum_cmp(lhs->y, rhs->y);
- if (ret) {
- ret = 1;
- }
- }
- ec_point_free(lhs);
- ec_point_free(rhs);
- }
- } else {
- Bignum r, s;
- unsigned char digest[512 / 8];
- void *hashctx;
- r = getmp(&p, &slen);
- if (!r) return 0;
- s = getmp(&p, &slen);
- if (!s) {
- freebn(r);
- return 0;
- }
- digestLen = extra->hash->hlen;
- assert(digestLen <= sizeof(digest));
- hashctx = extra->hash->init();
- extra->hash->bytes(hashctx, data, datalen);
- extra->hash->final(hashctx, digest);
- /* Verify the signature */
- ret = _ecdsa_verify(&ec->publicKey, digest, digestLen, r, s);
- freebn(r);
- freebn(s);
- }
- return ret;
- }
- static unsigned char *ecdsa_sign(void *key, const char *data, int datalen,
- int *siglen)
- {
- struct ec_key *ec = (struct ec_key *) key;
- const struct ecsign_extra *extra =
- (const struct ecsign_extra *)ec->signalg->extra;
- unsigned char digest[512 / 8];
- int digestLen;
- Bignum r = NULL, s = NULL;
- unsigned char *buf, *p;
- int rlen, slen, namelen;
- int i;
- if (!ec->privateKey || !ec->publicKey.curve) {
- return NULL;
- }
- if (ec->publicKey.curve->type == EC_EDWARDS) {
- struct ec_point *rp;
- int pointlen = ec->publicKey.curve->fieldBits / 8;
- /* hash = H(sk) (where hash creates 2 * fieldBits)
- * b = fieldBits
- * a = 2^(b-2) + SUM(2^i * h_i) for i = 2 -> b-2
- * r = H(h[b/8:b/4] + m)
- * R = rB
- * S = (r + H(encodepoint(R) + encodepoint(pk) + m) * a) % l */
- {
- unsigned char hash[512/8];
- unsigned char b;
- Bignum a;
- SHA512_State hs;
- SHA512_Init(&hs);
- for (i = 0; i < pointlen; ++i) {
- unsigned char b = (unsigned char)bignum_byte(ec->privateKey, i);
- SHA512_Bytes(&hs, &b, 1);
- }
- SHA512_Final(&hs, hash);
- /* The second part is simply turning the hash into a
- * Bignum, however the 2^(b-2) bit *must* be set, and the
- * bottom 3 bits *must* not be */
- hash[0] &= 0xf8; /* Unset bottom 3 bits (if set) */
- hash[31] &= 0x7f; /* Unset above (b-2) */
- hash[31] |= 0x40; /* Set 2^(b-2) */
- /* Chop off the top part and convert to int */
- a = bignum_from_bytes_le(hash, 32);
- SHA512_Init(&hs);
- SHA512_Bytes(&hs,
- hash+(ec->publicKey.curve->fieldBits / 8),
- (ec->publicKey.curve->fieldBits / 4)
- - (ec->publicKey.curve->fieldBits / 8));
- SHA512_Bytes(&hs, data, datalen);
- SHA512_Final(&hs, hash);
- r = bignum_from_bytes_le(hash, 512/8);
- rp = ecp_mul(&ec->publicKey.curve->e.B, r);
- if (!rp) {
- freebn(r);
- freebn(a);
- return NULL;
- }
- /* Now calculate s */
- SHA512_Init(&hs);
- /* Encode the point R */
- for (i = 0; i < pointlen - 1; ++i) {
- b = bignum_byte(rp->y, i);
- SHA512_Bytes(&hs, &b, 1);
- }
- /* Unset last bit of y and set first bit of x in its place */
- b = bignum_byte(rp->y, i) & 0x7f;
- b |= bignum_bit(rp->x, 0) << 7;
- SHA512_Bytes(&hs, &b, 1);
- /* Encode the point pk */
- for (i = 0; i < pointlen - 1; ++i) {
- b = bignum_byte(ec->publicKey.y, i);
- SHA512_Bytes(&hs, &b, 1);
- }
- /* Unset last bit of y and set first bit of x in its place */
- b = bignum_byte(ec->publicKey.y, i) & 0x7f;
- b |= bignum_bit(ec->publicKey.x, 0) << 7;
- SHA512_Bytes(&hs, &b, 1);
- /* Add the message */
- SHA512_Bytes(&hs, data, datalen);
- SHA512_Final(&hs, hash);
- {
- Bignum tmp, tmp2;
- tmp = bignum_from_bytes_le(hash, 512/8);
- tmp2 = modmul(tmp, a, ec->publicKey.curve->e.l);
- freebn(a);
- freebn(tmp);
- tmp = bigadd(r, tmp2);
- freebn(r);
- freebn(tmp2);
- s = bigmod(tmp, ec->publicKey.curve->e.l);
- freebn(tmp);
- }
- }
- /* Format the output */
- namelen = strlen(ec->signalg->name);
- *siglen = 4+namelen+4+((ec->publicKey.curve->fieldBits / 8)*2);
- buf = snewn(*siglen, unsigned char);
- p = buf;
- PUT_32BIT(p, namelen);
- p += 4;
- memcpy(p, ec->signalg->name, namelen);
- p += namelen;
- PUT_32BIT(p, ((ec->publicKey.curve->fieldBits / 8)*2));
- p += 4;
- /* Encode the point */
- pointlen = ec->publicKey.curve->fieldBits / 8;
- for (i = 0; i < pointlen - 1; ++i) {
- *p++ = bignum_byte(rp->y, i);
- }
- /* Unset last bit of y and set first bit of x in its place */
- *p = bignum_byte(rp->y, i) & 0x7f;
- *p++ |= bignum_bit(rp->x, 0) << 7;
- ec_point_free(rp);
- /* Encode the int */
- for (i = 0; i < pointlen; ++i) {
- *p++ = bignum_byte(s, i);
- }
- freebn(s);
- } else {
- void *hashctx;
- digestLen = extra->hash->hlen;
- assert(digestLen <= sizeof(digest));
- hashctx = extra->hash->init();
- extra->hash->bytes(hashctx, data, datalen);
- extra->hash->final(hashctx, digest);
- /* Do the signature */
- _ecdsa_sign(ec->privateKey, ec->publicKey.curve, digest, digestLen, &r, &s);
- if (!r || !s) {
- if (r) freebn(r);
- if (s) freebn(s);
- return NULL;
- }
- rlen = (bignum_bitcount(r) + 8) / 8;
- slen = (bignum_bitcount(s) + 8) / 8;
- namelen = strlen(ec->signalg->name);
- /* Format the output */
- *siglen = 8+namelen+rlen+slen+8;
- buf = snewn(*siglen, unsigned char);
- p = buf;
- PUT_32BIT(p, namelen);
- p += 4;
- memcpy(p, ec->signalg->name, namelen);
- p += namelen;
- PUT_32BIT(p, rlen + slen + 8);
- p += 4;
- PUT_32BIT(p, rlen);
- p += 4;
- for (i = rlen; i--;)
- *p++ = bignum_byte(r, i);
- PUT_32BIT(p, slen);
- p += 4;
- for (i = slen; i--;)
- *p++ = bignum_byte(s, i);
- freebn(r);
- freebn(s);
- }
- return buf;
- }
- const struct ecsign_extra sign_extra_ed25519 = {
- ec_ed25519, NULL,
- NULL, 0,
- };
- const struct ssh_signkey ssh_ecdsa_ed25519 = {
- ecdsa_newkey,
- ecdsa_freekey,
- ecdsa_fmtkey,
- ecdsa_public_blob,
- ecdsa_private_blob,
- ecdsa_createkey,
- ed25519_openssh_createkey,
- ed25519_openssh_fmtkey,
- 2 /* point, private exponent */,
- ecdsa_pubkey_bits,
- ecdsa_verifysig,
- ecdsa_sign,
- "ssh-ed25519",
- "ssh-ed25519",
- &sign_extra_ed25519,
- };
- /* OID: 1.2.840.10045.3.1.7 (ansiX9p256r1) */
- static const unsigned char nistp256_oid[] = {
- 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
- };
- const struct ecsign_extra sign_extra_nistp256 = {
- ec_p256, &ssh_sha256,
- nistp256_oid, lenof(nistp256_oid),
- };
- const struct ssh_signkey ssh_ecdsa_nistp256 = {
- ecdsa_newkey,
- ecdsa_freekey,
- ecdsa_fmtkey,
- ecdsa_public_blob,
- ecdsa_private_blob,
- ecdsa_createkey,
- ecdsa_openssh_createkey,
- ecdsa_openssh_fmtkey,
- 3 /* curve name, point, private exponent */,
- ecdsa_pubkey_bits,
- ecdsa_verifysig,
- ecdsa_sign,
- "ecdsa-sha2-nistp256",
- "ecdsa-sha2-nistp256",
- &sign_extra_nistp256,
- };
- /* OID: 1.3.132.0.34 (secp384r1) */
- static const unsigned char nistp384_oid[] = {
- 0x2b, 0x81, 0x04, 0x00, 0x22
- };
- const struct ecsign_extra sign_extra_nistp384 = {
- ec_p384, &ssh_sha384,
- nistp384_oid, lenof(nistp384_oid),
- };
- const struct ssh_signkey ssh_ecdsa_nistp384 = {
- ecdsa_newkey,
- ecdsa_freekey,
- ecdsa_fmtkey,
- ecdsa_public_blob,
- ecdsa_private_blob,
- ecdsa_createkey,
- ecdsa_openssh_createkey,
- ecdsa_openssh_fmtkey,
- 3 /* curve name, point, private exponent */,
- ecdsa_pubkey_bits,
- ecdsa_verifysig,
- ecdsa_sign,
- "ecdsa-sha2-nistp384",
- "ecdsa-sha2-nistp384",
- &sign_extra_nistp384,
- };
- /* OID: 1.3.132.0.35 (secp521r1) */
- static const unsigned char nistp521_oid[] = {
- 0x2b, 0x81, 0x04, 0x00, 0x23
- };
- const struct ecsign_extra sign_extra_nistp521 = {
- ec_p521, &ssh_sha512,
- nistp521_oid, lenof(nistp521_oid),
- };
- const struct ssh_signkey ssh_ecdsa_nistp521 = {
- ecdsa_newkey,
- ecdsa_freekey,
- ecdsa_fmtkey,
- ecdsa_public_blob,
- ecdsa_private_blob,
- ecdsa_createkey,
- ecdsa_openssh_createkey,
- ecdsa_openssh_fmtkey,
- 3 /* curve name, point, private exponent */,
- ecdsa_pubkey_bits,
- ecdsa_verifysig,
- ecdsa_sign,
- "ecdsa-sha2-nistp521",
- "ecdsa-sha2-nistp521",
- &sign_extra_nistp521,
- };
- /* ----------------------------------------------------------------------
- * Exposed ECDH interface
- */
- struct eckex_extra {
- struct ec_curve *(*curve)(void);
- int low_byte_mask, high_byte_top_bit;
- };
- static Bignum ecdh_calculate(const Bignum private,
- const struct ec_point *public)
- {
- struct ec_point *p;
- Bignum ret;
- p = ecp_mul(public, private);
- if (!p) return NULL;
- ret = p->x;
- p->x = NULL;
- if (p->curve->type == EC_MONTGOMERY) {
- /*
- * Endianness-swap. The Curve25519 algorithm definition
- * assumes you were doing your computation in arrays of 32
- * little-endian bytes, and now specifies that you take your
- * final one of those and convert it into a bignum in
- * _network_ byte order, i.e. big-endian.
- *
- * In particular, the spec says, you convert the _whole_ 32
- * bytes into a bignum. That is, on the rare occasions that
- * p->x has come out with the most significant 8 bits zero, we
- * have to imagine that being represented by a 32-byte string
- * with the last byte being zero, so that has to be converted
- * into an SSH-2 bignum with the _low_ byte zero, i.e. a
- * multiple of 256.
- */
- int i;
- int bytes = (p->curve->fieldBits+7) / 8;
- unsigned char *byteorder = snewn(bytes, unsigned char);
- for (i = 0; i < bytes; ++i) {
- byteorder[i] = bignum_byte(ret, i);
- }
- freebn(ret);
- ret = bignum_from_bytes(byteorder, bytes);
- smemclr(byteorder, bytes);
- sfree(byteorder);
- }
- ec_point_free(p);
- return ret;
- }
- const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex)
- {
- const struct eckex_extra *extra = (const struct eckex_extra *)kex->extra;
- struct ec_curve *curve = extra->curve();
- return curve->textname;
- }
- void *ssh_ecdhkex_newkey(const struct ssh_kex *kex)
- {
- const struct eckex_extra *extra = (const struct eckex_extra *)kex->extra;
- struct ec_curve *curve;
- struct ec_key *key;
- struct ec_point *publicKey;
- curve = extra->curve();
- key = snew(struct ec_key);
- key->signalg = NULL;
- key->publicKey.curve = curve;
- if (curve->type == EC_MONTGOMERY) {
- int nbytes = (curve->fieldBits+7) / 8;
- unsigned char bytes[56] = {0};
- int i;
- assert(nbytes <= lenof(bytes));
- for (i = 0; i < nbytes; ++i)
- {
- bytes[i] = (unsigned char)random_byte();
- }
- bytes[0] &= extra->low_byte_mask;
- bytes[nbytes-1] &= extra->high_byte_top_bit - 1;
- bytes[nbytes-1] |= extra->high_byte_top_bit;
- key->privateKey = bignum_from_bytes_le(bytes, nbytes);
- smemclr(bytes, nbytes);
- if (!key->privateKey) {
- sfree(key);
- return NULL;
- }
- publicKey = ecp_mul(&key->publicKey.curve->m.G, key->privateKey);
- if (!publicKey) {
- freebn(key->privateKey);
- sfree(key);
- return NULL;
- }
- key->publicKey.x = publicKey->x;
- key->publicKey.y = publicKey->y;
- key->publicKey.z = NULL;
- sfree(publicKey);
- } else {
- key->privateKey = bignum_random_in_range(One, key->publicKey.curve->w.n);
- if (!key->privateKey) {
- sfree(key);
- return NULL;
- }
- publicKey = ecp_mul(&key->publicKey.curve->w.G, key->privateKey);
- if (!publicKey) {
- freebn(key->privateKey);
- sfree(key);
- return NULL;
- }
- key->publicKey.x = publicKey->x;
- key->publicKey.y = publicKey->y;
- key->publicKey.z = NULL;
- sfree(publicKey);
- }
- return key;
- }
- char *ssh_ecdhkex_getpublic(void *key, int *len)
- {
- struct ec_key *ec = (struct ec_key*)key;
- char *point, *p;
- int i;
- int pointlen;
- pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
- if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
- *len = 1 + pointlen * 2;
- } else {
- *len = pointlen;
- }
- point = (char*)snewn(*len, char);
- p = point;
- if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
- *p++ = 0x04;
- for (i = pointlen; i--;) {
- *p++ = bignum_byte(ec->publicKey.x, i);
- }
- for (i = pointlen; i--;) {
- *p++ = bignum_byte(ec->publicKey.y, i);
- }
- } else {
- for (i = 0; i < pointlen; ++i) {
- *p++ = bignum_byte(ec->publicKey.x, i);
- }
- }
- return point;
- }
- Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen)
- {
- struct ec_key *ec = (struct ec_key*) key;
- struct ec_point remote;
- Bignum ret;
- if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
- remote.curve = ec->publicKey.curve;
- remote.infinity = 0;
- if (!decodepoint(remoteKey, remoteKeyLen, &remote)) {
- return NULL;
- }
- } else {
- /* Point length has to be the same length */
- if (remoteKeyLen != (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8) {
- return NULL;
- }
- remote.curve = ec->publicKey.curve;
- remote.infinity = 0;
- remote.x = bignum_from_bytes_le((unsigned char*)remoteKey, remoteKeyLen);
- remote.y = NULL;
- remote.z = NULL;
- }
- ret = ecdh_calculate(ec->privateKey, &remote);
- if (remote.x) freebn(remote.x);
- if (remote.y) freebn(remote.y);
- return ret;
- }
- void ssh_ecdhkex_freekey(void *key)
- {
- ecdsa_freekey(key);
- }
- static const struct eckex_extra kex_extra_curve25519 = {
- ec_curve25519, 0xF8, 0x40,
- };
- static const struct ssh_kex ssh_ec_kex_curve25519 = {
- "curve25519-sha256@libssh.org", NULL, KEXTYPE_ECDH,
- &ssh_sha256, &kex_extra_curve25519,
- };
- static const struct eckex_extra kex_extra_curve448 = {
- ec_curve448, 0xFC, 0x80,
- };
- static const struct ssh_kex ssh_ec_kex_curve448 = {
- "curve448-sha512", NULL, KEXTYPE_ECDH,
- &ssh_sha512, &kex_extra_curve448,
- };
- const struct eckex_extra kex_extra_nistp256 = { ec_p256 };
- static const struct ssh_kex ssh_ec_kex_nistp256 = {
- "ecdh-sha2-nistp256", NULL, KEXTYPE_ECDH,
- &ssh_sha256, &kex_extra_nistp256,
- };
- const struct eckex_extra kex_extra_nistp384 = { ec_p384 };
- static const struct ssh_kex ssh_ec_kex_nistp384 = {
- "ecdh-sha2-nistp384", NULL, KEXTYPE_ECDH,
- &ssh_sha384, &kex_extra_nistp384,
- };
- const struct eckex_extra kex_extra_nistp521 = { ec_p521 };
- static const struct ssh_kex ssh_ec_kex_nistp521 = {
- "ecdh-sha2-nistp521", NULL, KEXTYPE_ECDH,
- &ssh_sha512, &kex_extra_nistp521,
- };
- static const struct ssh_kex *const ec_kex_list[] = {
- &ssh_ec_kex_curve448,
- &ssh_ec_kex_curve25519,
- &ssh_ec_kex_nistp256,
- &ssh_ec_kex_nistp384,
- &ssh_ec_kex_nistp521,
- };
- const struct ssh_kexes ssh_ecdh_kex = {
- sizeof(ec_kex_list) / sizeof(*ec_kex_list),
- ec_kex_list
- };
- /* ----------------------------------------------------------------------
- * Helper functions for finding key algorithms and returning auxiliary
- * data.
- */
- const struct ssh_signkey *ec_alg_by_oid(int len, const void *oid,
- const struct ec_curve **curve)
- {
- static const struct ssh_signkey *algs_with_oid[] = {
- &ssh_ecdsa_nistp256,
- &ssh_ecdsa_nistp384,
- &ssh_ecdsa_nistp521,
- };
- int i;
- for (i = 0; i < lenof(algs_with_oid); i++) {
- const struct ssh_signkey *alg = algs_with_oid[i];
- const struct ecsign_extra *extra =
- (const struct ecsign_extra *)alg->extra;
- if (len == extra->oidlen && !memcmp(oid, extra->oid, len)) {
- *curve = extra->curve();
- return alg;
- }
- }
- return NULL;
- }
- const unsigned char *ec_alg_oid(const struct ssh_signkey *alg,
- int *oidlen)
- {
- const struct ecsign_extra *extra = (const struct ecsign_extra *)alg->extra;
- *oidlen = extra->oidlen;
- return extra->oid;
- }
- const int ec_nist_curve_lengths[] = { 256, 384, 521 };
- const int n_ec_nist_curve_lengths = lenof(ec_nist_curve_lengths);
- const int ec_nist_alg_and_curve_by_bits(int bits,
- const struct ec_curve **curve,
- const struct ssh_signkey **alg)
- {
- switch (bits) {
- case 256: *alg = &ssh_ecdsa_nistp256; break;
- case 384: *alg = &ssh_ecdsa_nistp384; break;
- case 521: *alg = &ssh_ecdsa_nistp521; break;
- default: return FALSE;
- }
- *curve = ((struct ecsign_extra *)(*alg)->extra)->curve();
- return TRUE;
- }
- const int ec_ed_alg_and_curve_by_bits(int bits,
- const struct ec_curve **curve,
- const struct ssh_signkey **alg)
- {
- switch (bits) {
- case 256: *alg = &ssh_ecdsa_ed25519; break;
- default: return FALSE;
- }
- *curve = ((struct ecsign_extra *)(*alg)->extra)->curve();
- return TRUE;
- }
|