/* Make an RSA key for size bits, with e specified, 65537 is a good e */ int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng) { mp_int p, q, tmp1, tmp2, tmp3; int err; if (key == NULL || rng == NULL) return BAD_FUNC_ARG; if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE) return BAD_FUNC_ARG; if (e < 3 || (e & 1) == 0) return BAD_FUNC_ARG; if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) return err; err = mp_set_int(&tmp3, e); /* make p */ if (err == MP_OKAY) { do { err = rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */ if (err == MP_OKAY) err = mp_sub_d(&p, 1, &tmp1); /* tmp1 = p-1 */ if (err == MP_OKAY) err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(p-1, e) */ } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes p-1 */ } /* make q */ if (err == MP_OKAY) { do { err = rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */ if (err == MP_OKAY) err = mp_sub_d(&q, 1, &tmp1); /* tmp1 = q-1 */ if (err == MP_OKAY) err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(q-1, e) */ } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes q-1 */ } if (err == MP_OKAY) err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL); if (err == MP_OKAY) err = mp_init_multi(&key->dP, &key->dQ, &key->u, NULL, NULL, NULL); if (err == MP_OKAY) err = mp_sub_d(&p, 1, &tmp2); /* tmp2 = p-1 */ if (err == MP_OKAY) err = mp_lcm(&tmp1, &tmp2, &tmp1); /* tmp1 = lcm(p-1, q-1),last loop */ /* make key */ if (err == MP_OKAY) err = mp_set_int(&key->e, e); /* key->e = e */ if (err == MP_OKAY) /* key->d = 1/e mod lcm(p-1, q-1) */ err = mp_invmod(&key->e, &tmp1, &key->d); if (err == MP_OKAY) err = mp_mul(&p, &q, &key->n); /* key->n = pq */ if (err == MP_OKAY) err = mp_sub_d(&p, 1, &tmp1); if (err == MP_OKAY) err = mp_sub_d(&q, 1, &tmp2); if (err == MP_OKAY) err = mp_mod(&key->d, &tmp1, &key->dP); if (err == MP_OKAY) err = mp_mod(&key->d, &tmp2, &key->dQ); if (err == MP_OKAY) err = mp_invmod(&q, &p, &key->u); if (err == MP_OKAY) err = mp_copy(&p, &key->p); if (err == MP_OKAY) err = mp_copy(&q, &key->q); if (err == MP_OKAY) key->type = RSA_PRIVATE; mp_clear(&tmp3); mp_clear(&tmp2); mp_clear(&tmp1); mp_clear(&q); mp_clear(&p); if (err != MP_OKAY) { FreeRsaKey(key); return err; } return 0; }
static SECStatus rsa_keygen_from_primes(mp_int *p, mp_int *q, mp_int *e, RSAPrivateKey *key, unsigned int keySizeInBits) { mp_int n, d, phi; mp_int psub1, qsub1, tmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&phi) = 0; MP_DIGITS(&psub1) = 0; MP_DIGITS(&qsub1) = 0; MP_DIGITS(&tmp) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&phi) ); CHECK_MPI_OK( mp_init(&psub1) ); CHECK_MPI_OK( mp_init(&qsub1) ); CHECK_MPI_OK( mp_init(&tmp) ); /* 1. Compute n = p*q */ CHECK_MPI_OK( mp_mul(p, q, &n) ); /* verify that the modulus has the desired number of bits */ if ((unsigned)mpl_significant_bits(&n) != keySizeInBits) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* 2. Compute phi = (p-1)*(q-1) */ CHECK_MPI_OK( mp_sub_d(p, 1, &psub1) ); CHECK_MPI_OK( mp_sub_d(q, 1, &qsub1) ); CHECK_MPI_OK( mp_mul(&psub1, &qsub1, &phi) ); /* 3. Compute d = e**-1 mod(phi) */ err = mp_invmod(e, &phi, &d); /* Verify that phi(n) and e have no common divisors */ if (err != MP_OKAY) { if (err == MP_UNDEF) { PORT_SetError(SEC_ERROR_NEED_RANDOM); err = MP_OKAY; /* to keep PORT_SetError from being called again */ rv = SECFailure; } goto cleanup; } MPINT_TO_SECITEM(&n, &key->modulus, key->arena); MPINT_TO_SECITEM(&d, &key->privateExponent, key->arena); /* 4. Compute exponent1 = d mod (p-1) */ CHECK_MPI_OK( mp_mod(&d, &psub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent1, key->arena); /* 5. Compute exponent2 = d mod (q-1) */ CHECK_MPI_OK( mp_mod(&d, &qsub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent2, key->arena); /* 6. Compute coefficient = q**-1 mod p */ CHECK_MPI_OK( mp_invmod(q, p, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->coefficient, key->arena); cleanup: mp_clear(&n); mp_clear(&d); mp_clear(&phi); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&tmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng) { mp_int k, kInv, r, s, H; int ret = 0, sz; byte buffer[DSA_HALF_SIZE]; if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY) return MP_INIT_E; sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q)); /* generate k */ RNG_GenerateBlock(rng, buffer, sz); buffer[0] |= 0x0C; if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY) ret = MP_READ_E; if (mp_cmp_d(&k, 1) != MP_GT) assert(0); /* inverse k mod q */ if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY) ret = MP_INVMOD_E; /* generate r, r = (g exp k mod p) mod q */ if (ret == 0 && mp_exptmod(&key->g, &k, &key->p, &r) != MP_OKAY) ret = MP_EXPTMOD_E; if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY) ret = MP_MOD_E; /* generate H from sha digest */ if (ret == 0 && mp_read_unsigned_bin(&H, digest,SHA_DIGEST_SIZE) != MP_OKAY) ret = MP_READ_E; /* generate s, s = (kInv * (H + x*r)) % q */ if (ret == 0 && mp_mul(&key->x, &r, &s) != MP_OKAY) ret = MP_MUL_E; if (ret == 0 && mp_add(&s, &H, &s) != MP_OKAY) ret = MP_ADD_E; if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY) ret = MP_MULMOD_E; /* write out */ if (ret == 0) { int rSz = mp_unsigned_bin_size(&r); int sSz = mp_unsigned_bin_size(&s); if (rSz == DSA_HALF_SIZE - 1) { out[0] = 0; out++; } if (mp_to_unsigned_bin(&r, out) != MP_OKAY) ret = MP_TO_E; else { if (sSz == DSA_HALF_SIZE - 1) { out[rSz] = 0; out++; } ret = mp_to_unsigned_bin(&s, out + rSz); } } mp_clear(&H); mp_clear(&s); mp_clear(&r); mp_clear(&kInv); mp_clear(&k); return ret; }
/*------------------------------------------------------------------*/ int32 read_poly(msieve_obj *obj, mp_t *n, mp_poly_t *rat_poly, mp_poly_t *alg_poly, double *skewness) { int32 i; FILE *fp; char buf[LINE_BUF_SIZE]; mp_t read_n; signed_mp_t val, rpow, tmp; fp = fopen(obj->nfs_fbfile_name, "r"); if (fp == NULL) return -1; buf[0] = 0; fgets(buf, (int)sizeof(buf), fp); if (buf[0] != 'N') { fclose(fp); logprintf(obj, "warning: factor base file uninitialized\n"); return -1; } /* check that the polynomial is for the right number */ mp_str2mp(buf + 2, &read_n, 10); if (mp_cmp(&read_n, n)) { fclose(fp); logprintf(obj, "warning: NFS input not found in " "factor base file\n"); return -1; } /* read in skewness if present */ fgets(buf, (int)sizeof(buf), fp); if (buf[0] == 'S') { if (skewness != NULL) *skewness = atof(buf + 5); fgets(buf, (int)sizeof(buf), fp); } else if (skewness != NULL) { *skewness = 1.0; } /* read one coefficient per line; 'R<number>' is for rational coefficients, 'A<number>' for algebraic */ while ((buf[0] == 'R' || buf[0] == 'A') && isdigit(buf[1])) { signed_mp_t *read_coeff; char *tmp; i = buf[1] - '0'; if (i > MAX_POLY_DEGREE) { fclose(fp); logprintf(obj, "warning: polynomial degree exceeds " "%d\n", MAX_POLY_DEGREE); exit(-1); } if (buf[0] == 'R') read_coeff = rat_poly->coeff + i; else read_coeff = alg_poly->coeff + i; tmp = buf + 2; while (isspace(*tmp)) tmp++; if (*tmp == '-') { read_coeff->sign = NEGATIVE; tmp++; } else { read_coeff->sign = POSITIVE; } mp_str2mp(tmp, &read_coeff->num, 10); if (fgets(buf, (int)sizeof(buf), fp) == NULL) break; } for (i = MAX_POLY_DEGREE; i >= 0; i--) { if (!mp_is_zero(&rat_poly->coeff[i].num)) break; } if (i > 0) rat_poly->degree = i; for (i = MAX_POLY_DEGREE; i >= 0; i--) { if (!mp_is_zero(&alg_poly->coeff[i].num)) break; } if (i > 0) alg_poly->degree = i; fclose(fp); if (rat_poly->degree == 0 || alg_poly->degree == 0) { logprintf(obj, "error: polynomial is missing or corrupt\n"); exit(-1); } if (rat_poly->degree != 1) { logprintf(obj, "error: no support for nonlinear " "rational polynomials\n"); exit(-1); } /* plug the rational polynomial coefficients into the algebraic polynomial */ i = alg_poly->degree; signed_mp_copy(alg_poly->coeff + i, &val); signed_mp_copy(rat_poly->coeff + 1, &rpow); for (i--; i >= 0; i--) { signed_mp_mul(&val, rat_poly->coeff + 0, &tmp); tmp.sign = (tmp.sign == POSITIVE) ? NEGATIVE : POSITIVE; signed_mp_copy(&tmp, &val); signed_mp_mul(alg_poly->coeff + i, &rpow, &tmp); signed_mp_add(&val, &tmp, &val); signed_mp_mul(rat_poly->coeff + 1, &rpow, &tmp); signed_mp_copy(&tmp, &rpow); } /* verify that |result| >= N, and that result % N == 0. The only place where we do any mod-N arithmetic is the NFS square root, which will not work if N has additional factors that are not reflected in the polynomials */ if ((i = mp_cmp(&val.num, n)) < 0) { logprintf(obj, "error: NFS input does not match polynomials\n"); logprintf(obj, "check that input doesn't have small factors\n"); exit(-1); } else if (i > 0) { mp_mod(&val.num, n, &read_n); if (!mp_is_zero(&read_n)) { logprintf(obj, "error: NFS input does not " "match polynomials\n"); exit(-1); } } return 0; }
int main(void) { ulong64 tt, gg, CLK_PER_SEC; FILE *log, *logb, *logc, *logd; mp_int a, b, c, d, e, f; int n, cnt, ix, old_kara_m, old_kara_s; unsigned rr; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); mp_init(&f); srand(time(NULL)); /* temp. turn off TOOM */ TOOM_MUL_CUTOFF = TOOM_SQR_CUTOFF = 100000; CLK_PER_SEC = TIMFUNC(); sleep(1); CLK_PER_SEC = TIMFUNC() - CLK_PER_SEC; printf("CLK_PER_SEC == %llu\n", CLK_PER_SEC); goto exptmod; log = fopen("logs/add.log", "w"); for (cnt = 8; cnt <= 128; cnt += 8) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_add(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100000); printf("Adding\t\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); fflush(log); } fclose(log); log = fopen("logs/sub.log", "w"); for (cnt = 8; cnt <= 128; cnt += 8) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_sub(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100000); printf("Subtracting\t\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); fflush(log); } fclose(log); /* do mult/square twice, first without karatsuba and second with */ multtest: old_kara_m = KARATSUBA_MUL_CUTOFF; old_kara_s = KARATSUBA_SQR_CUTOFF; for (ix = 0; ix < 2; ix++) { printf("With%s Karatsuba\n", (ix == 0) ? "out" : ""); KARATSUBA_MUL_CUTOFF = (ix == 0) ? 9999 : old_kara_m; KARATSUBA_SQR_CUTOFF = (ix == 0) ? 9999 : old_kara_s; log = fopen((ix == 0) ? "logs/mult.log" : "logs/mult_kara.log", "w"); for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_mul(&a, &b, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100); printf("Multiplying\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); fflush(log); } fclose(log); log = fopen((ix == 0) ? "logs/sqr.log" : "logs/sqr_kara.log", "w"); for (cnt = 4; cnt <= 10240 / DIGIT_BIT; cnt += 2) { SLEEP; mp_rand(&a, cnt); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_sqr(&a, &b)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 100); printf("Squaring\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", mp_count_bits(&a), tt); fflush(log); } fclose(log); } exptmod: { char *primes[] = { /* 2K large moduli */ "179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586239334100047359817950870678242457666208137217", "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638099733077152121140120031150424541696791951097529546801429027668869927491725169", "1044388881413152506691752710716624382579964249047383780384233483283953907971557456848826811934997558340890106714439262837987573438185793607263236087851365277945956976543709998340361590134383718314428070011855946226376318839397712745672334684344586617496807908705803704071284048740118609114467977783598029006686938976881787785946905630190260940599579453432823469303026696443059025015972399867714215541693835559885291486318237914434496734087811872639496475100189041349008417061675093668333850551032972088269550769983616369411933015213796825837188091833656751221318492846368125550225998300412344784862595674492194617023806505913245610825731835380087608622102834270197698202313169017678006675195485079921636419370285375124784014907159135459982790513399611551794271106831134090584272884279791554849782954323534517065223269061394905987693002122963395687782878948440616007412945674919823050571642377154816321380631045902916136926708342856440730447899971901781465763473223850267253059899795996090799469201774624817718449867455659250178329070473119433165550807568221846571746373296884912819520317457002440926616910874148385078411929804522981857338977648103126085902995208257421855249796721729039744118165938433694823325696642096892124547425283", /* 2K moduli mersenne primes */ "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", "531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127", "10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087", "1475979915214180235084898622737381736312066145333169775147771216478570297878078949377407337049389289382748507531496480477281264838760259191814463365330269540496961201113430156902396093989090226259326935025281409614983499388222831448598601834318536230923772641390209490231836446899608210795482963763094236630945410832793769905399982457186322944729636418890623372171723742105636440368218459649632948538696905872650486914434637457507280441823676813517852099348660847172579408422316678097670224011990280170474894487426924742108823536808485072502240519452587542875349976558572670229633962575212637477897785501552646522609988869914013540483809865681250419497686697771007", "259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071", "190797007524439073807468042969529173669356994749940177394741882673528979787005053706368049835514900244303495954950709725762186311224148828811920216904542206960744666169364221195289538436845390250168663932838805192055137154390912666527533007309292687539092257043362517857366624699975402375462954490293259233303137330643531556539739921926201438606439020075174723029056838272505051571967594608350063404495977660656269020823960825567012344189908927956646011998057988548630107637380993519826582389781888135705408653045219655801758081251164080554609057468028203308718724654081055323215860189611391296030471108443146745671967766308925858547271507311563765171008318248647110097614890313562856541784154881743146033909602737947385055355960331855614540900081456378659068370317267696980001187750995491090350108417050917991562167972281070161305972518044872048331306383715094854938415738549894606070722584737978176686422134354526989443028353644037187375385397838259511833166416134323695660367676897722287918773420968982326089026150031515424165462111337527431154890666327374921446276833564519776797633875503548665093914556482031482248883127023777039667707976559857333357013727342079099064400455741830654320379350833236245819348824064783585692924881021978332974949906122664421376034687815350484991", /* DR moduli */ "14059105607947488696282932836518693308967803494693489478439861164411992439598399594747002144074658928593502845729752797260025831423419686528151609940203368612079", "101745825697019260773923519755878567461315282017759829107608914364075275235254395622580447400994175578963163918967182013639660669771108475957692810857098847138903161308502419410142185759152435680068435915159402496058513611411688900243039", "736335108039604595805923406147184530889923370574768772191969612422073040099331944991573923112581267542507986451953227192970402893063850485730703075899286013451337291468249027691733891486704001513279827771740183629161065194874727962517148100775228363421083691764065477590823919364012917984605619526140821797602431", "38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165162175783", "542189391331696172661670440619180536749994166415993334151601745392193484590296600979602378676624808129613777993466242203025054573692562689251250471628358318743978285860720148446448885701001277560572526947619392551574490839286458454994488665744991822837769918095117129546414124448777033941223565831420390846864429504774477949153794689948747680362212954278693335653935890352619041936727463717926744868338358149568368643403037768649616778526013610493696186055899318268339432671541328195724261329606699831016666359440874843103020666106568222401047720269951530296879490444224546654729111504346660859907296364097126834834235287147", "1487259134814709264092032648525971038895865645148901180585340454985524155135260217788758027400478312256339496385275012465661575576202252063145698732079880294664220579764848767704076761853197216563262660046602703973050798218246170835962005598561669706844469447435461092542265792444947706769615695252256130901271870341005768912974433684521436211263358097522726462083917939091760026658925757076733484173202927141441492573799914240222628795405623953109131594523623353044898339481494120112723445689647986475279242446083151413667587008191682564376412347964146113898565886683139407005941383669325997475076910488086663256335689181157957571445067490187939553165903773554290260531009121879044170766615232300936675369451260747671432073394867530820527479172464106442450727640226503746586340279816318821395210726268291535648506190714616083163403189943334431056876038286530365757187367147446004855912033137386225053275419626102417236133948503", "1095121115716677802856811290392395128588168592409109494900178008967955253005183831872715423151551999734857184538199864469605657805519106717529655044054833197687459782636297255219742994736751541815269727940751860670268774903340296040006114013971309257028332849679096824800250742691718610670812374272414086863715763724622797509437062518082383056050144624962776302147890521249477060215148275163688301275847155316042279405557632639366066847442861422164832655874655824221577849928863023018366835675399949740429332468186340518172487073360822220449055340582568461568645259954873303616953776393853174845132081121976327462740354930744487429617202585015510744298530101547706821590188733515880733527449780963163909830077616357506845523215289297624086914545378511082534229620116563260168494523906566709418166011112754529766183554579321224940951177394088465596712620076240067370589036924024728375076210477267488679008016579588696191194060127319035195370137160936882402244399699172017835144537488486396906144217720028992863941288217185353914991583400421682751000603596655790990815525126154394344641336397793791497068253936771017031980867706707490224041075826337383538651825493679503771934836094655802776331664261631740148281763487765852746577808019633679", /* generic unrestricted moduli */ "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", "2893527720709661239493896562339544088620375736490408468011883030469939904368086092336458298221245707898933583190713188177399401852627749210994595974791782790253946539043962213027074922559572312141181787434278708783207966459019479487", "347743159439876626079252796797422223177535447388206607607181663903045907591201940478223621722118173270898487582987137708656414344685816179420855160986340457973820182883508387588163122354089264395604796675278966117567294812714812796820596564876450716066283126720010859041484786529056457896367683122960411136319", "47266428956356393164697365098120418976400602706072312735924071745438532218237979333351774907308168340693326687317443721193266215155735814510792148768576498491199122744351399489453533553203833318691678263241941706256996197460424029012419012634671862283532342656309677173602509498417976091509154360039893165037637034737020327399910409885798185771003505320583967737293415979917317338985837385734747478364242020380416892056650841470869294527543597349250299539682430605173321029026555546832473048600327036845781970289288898317888427517364945316709081173840186150794397479045034008257793436817683392375274635794835245695887", "436463808505957768574894870394349739623346440601945961161254440072143298152040105676491048248110146278752857839930515766167441407021501229924721335644557342265864606569000117714935185566842453630868849121480179691838399545644365571106757731317371758557990781880691336695584799313313687287468894148823761785582982549586183756806449017542622267874275103877481475534991201849912222670102069951687572917937634467778042874315463238062009202992087620963771759666448266532858079402669920025224220613419441069718482837399612644978839925207109870840278194042158748845445131729137117098529028886770063736487420613144045836803985635654192482395882603511950547826439092832800532152534003936926017612446606135655146445620623395788978726744728503058670046885876251527122350275750995227", "11424167473351836398078306042624362277956429440521137061889702611766348760692206243140413411077394583180726863277012016602279290144126785129569474909173584789822341986742719230331946072730319555984484911716797058875905400999504305877245849119687509023232790273637466821052576859232452982061831009770786031785669030271542286603956118755585683996118896215213488875253101894663403069677745948305893849505434201763745232895780711972432011344857521691017896316861403206449421332243658855453435784006517202894181640562433575390821384210960117518650374602256601091379644034244332285065935413233557998331562749140202965844219336298970011513882564935538704289446968322281451907487362046511461221329799897350993370560697505809686438782036235372137015731304779072430260986460269894522159103008260495503005267165927542949439526272736586626709581721032189532726389643625590680105784844246152702670169304203783072275089194754889511973916207", "1214855636816562637502584060163403830270705000634713483015101384881871978446801224798536155406895823305035467591632531067547890948695117172076954220727075688048751022421198712032848890056357845974246560748347918630050853933697792254955890439720297560693579400297062396904306270145886830719309296352765295712183040773146419022875165382778007040109957609739589875590885701126197906063620133954893216612678838507540777138437797705602453719559017633986486649523611975865005712371194067612263330335590526176087004421363598470302731349138773205901447704682181517904064735636518462452242791676541725292378925568296858010151852326316777511935037531017413910506921922450666933202278489024521263798482237150056835746454842662048692127173834433089016107854491097456725016327709663199738238442164843147132789153725513257167915555162094970853584447993125488607696008169807374736711297007473812256272245489405898470297178738029484459690836250560495461579533254473316340608217876781986188705928270735695752830825527963838355419762516246028680280988020401914551825487349990306976304093109384451438813251211051597392127491464898797406789175453067960072008590614886532333015881171367104445044718144312416815712216611576221546455968770801413440778423979", NULL }; log = fopen("logs/expt.log", "w"); logb = fopen("logs/expt_dr.log", "w"); logc = fopen("logs/expt_2k.log", "w"); logd = fopen("logs/expt_2kl.log", "w"); for (n = 0; primes[n]; n++) { SLEEP; mp_read_radix(&a, primes[n], 10); mp_zero(&b); for (rr = 0; rr < (unsigned) mp_count_bits(&a); rr++) { mp_mul_2(&b, &b); OR_DIGIT(&b,0,lbit()) ; INC_USED(&b,1) ; } mp_sub_d(&a, 1, &c); mp_mod(&b, &c, &b); mp_set(&c, 3); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_exptmod(&c, &b, &a, &d)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 10); mp_sub_d(&a, 1, &e); mp_sub(&e, &b, &b); mp_exptmod(&c, &b, &a, &e); /* c^(p-1-b) mod a */ mp_mulmod(&e, &d, &a, &d); /* c^b * c^(p-1-b) == c^p-1 == 1 */ if (mp_cmp_d(&d, 1)) { printf("Different (%d)!!!\n", mp_count_bits(&a)); draw(&d); exit(0); } printf("Exponentiating\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(n < 4 ? logd : (n < 9) ? logc : (n < 16) ? logb : log, "%d %9llu\n", mp_count_bits(&a), tt); } } fclose(log); fclose(logb); fclose(logc); fclose(logd); log = fopen("logs/invmod.log", "w"); for (cnt = 4; cnt <= 128; cnt += 4) { SLEEP; mp_rand(&a, cnt); mp_rand(&b, cnt); do { mp_add_d(&b, 1, &b); mp_gcd(&a, &b, &c); } while (mp_cmp_d(&c, 1) != MP_EQ); rr = 0; tt = -1; do { gg = TIMFUNC(); DO(mp_invmod(&b, &a, &c)); gg = (TIMFUNC() - gg) >> 1; if (tt > gg) tt = gg; } while (++rr < 1000); mp_mulmod(&b, &c, &a, &d); if (mp_cmp_d(&d, 1) != MP_EQ) { printf("Failed to invert\n"); return 0; } printf("Inverting mod\t%4d-bit => %9llu/sec, %9llu cycles\n", mp_count_bits(&a), CLK_PER_SEC / tt, tt); fprintf(log, "%d %9llu\n", cnt * DIGIT_BIT, tt); } fclose(log); return 0; }
int main(void) { mp_int a, b, c, d, e, f; unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n, t; unsigned rr; int i, n, err, cnt, ix, old_kara_m, old_kara_s; mp_init(&a); mp_init(&b); mp_init(&c); mp_init(&d); mp_init(&e); mp_init(&f); srand(time(NULL)); #if 0 // test mp_get_int printf("Testing: mp_get_int\n"); for(i=0;i<1000;++i) { t = ((unsigned long)rand()*rand()+1)&0xFFFFFFFF; mp_set_int(&a,t); if (t!=mp_get_int(&a)) { printf("mp_get_int() bad result!\n"); return 1; } } mp_set_int(&a,0); if (mp_get_int(&a)!=0) { printf("mp_get_int() bad result!\n"); return 1; } mp_set_int(&a,0xffffffff); if (mp_get_int(&a)!=0xffffffff) { printf("mp_get_int() bad result!\n"); return 1; } // test mp_sqrt printf("Testing: mp_sqrt\n"); for (i=0;i<1000;++i) { printf("%6d\r", i); fflush(stdout); n = (rand()&15)+1; mp_rand(&a,n); if (mp_sqrt(&a,&b) != MP_OKAY) { printf("mp_sqrt() error!\n"); return 1; } mp_n_root(&a,2,&a); if (mp_cmp_mag(&b,&a) != MP_EQ) { printf("mp_sqrt() bad result!\n"); return 1; } } printf("\nTesting: mp_is_square\n"); for (i=0;i<1000;++i) { printf("%6d\r", i); fflush(stdout); /* test mp_is_square false negatives */ n = (rand()&7)+1; mp_rand(&a,n); mp_sqr(&a,&a); if (mp_is_square(&a,&n)!=MP_OKAY) { printf("fn:mp_is_square() error!\n"); return 1; } if (n==0) { printf("fn:mp_is_square() bad result!\n"); return 1; } /* test for false positives */ mp_add_d(&a, 1, &a); if (mp_is_square(&a,&n)!=MP_OKAY) { printf("fp:mp_is_square() error!\n"); return 1; } if (n==1) { printf("fp:mp_is_square() bad result!\n"); return 1; } } printf("\n\n"); /* test for size */ for (ix = 10; ix < 256; ix++) { printf("Testing (not safe-prime): %9d bits \r", ix); fflush(stdout); err = mp_prime_random_ex(&a, 8, ix, (rand()&1)?LTM_PRIME_2MSB_OFF:LTM_PRIME_2MSB_ON, myrng, NULL); if (err != MP_OKAY) { printf("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits(&a) != ix) { printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); return EXIT_FAILURE; } } for (ix = 16; ix < 256; ix++) { printf("Testing ( safe-prime): %9d bits \r", ix); fflush(stdout); err = mp_prime_random_ex(&a, 8, ix, ((rand()&1)?LTM_PRIME_2MSB_OFF:LTM_PRIME_2MSB_ON)|LTM_PRIME_SAFE, myrng, NULL); if (err != MP_OKAY) { printf("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits(&a) != ix) { printf("Prime is %d not %d bits!!!\n", mp_count_bits(&a), ix); return EXIT_FAILURE; } /* let's see if it's really a safe prime */ mp_sub_d(&a, 1, &a); mp_div_2(&a, &a); mp_prime_is_prime(&a, 8, &cnt); if (cnt != MP_YES) { printf("sub is not prime!\n"); return EXIT_FAILURE; } } printf("\n\n"); mp_read_radix(&a, "123456", 10); mp_toradix_n(&a, buf, 10, 3); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 4); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 30); printf("a == %s\n", buf); #if 0 for (;;) { fgets(buf, sizeof(buf), stdin); mp_read_radix(&a, buf, 10); mp_prime_next_prime(&a, 5, 1); mp_toradix(&a, buf, 10); printf("%s, %lu\n", buf, a.dp[0] & 3); } #endif /* test mp_cnt_lsb */ printf("testing mp_cnt_lsb...\n"); mp_set(&a, 1); for (ix = 0; ix < 1024; ix++) { if (mp_cnt_lsb(&a) != ix) { printf("Failed at %d, %d\n", ix, mp_cnt_lsb(&a)); return 0; } mp_mul_2(&a, &a); } /* test mp_reduce_2k */ printf("Testing mp_reduce_2k...\n"); for (cnt = 3; cnt <= 128; ++cnt) { mp_digit tmp; mp_2expt(&a, cnt); mp_sub_d(&a, 2, &a); /* a = 2**cnt - 2 */ printf("\nTesting %4d bits", cnt); printf("(%d)", mp_reduce_is_2k(&a)); mp_reduce_2k_setup(&a, &tmp); printf("(%d)", tmp); for (ix = 0; ix < 1000; ix++) { if (!(ix & 127)) {printf("."); fflush(stdout); } mp_rand(&b, (cnt/DIGIT_BIT + 1) * 2); mp_copy(&c, &b); mp_mod(&c, &a, &c); mp_reduce_2k(&b, &a, 1); if (mp_cmp(&c, &b)) { printf("FAILED\n"); exit(0); } } } /* test mp_div_3 */ printf("Testing mp_div_3...\n"); mp_set(&d, 3); for (cnt = 0; cnt < 10000; ) { mp_digit r1, r2; if (!(++cnt & 127)) printf("%9d\r", cnt); mp_rand(&a, abs(rand()) % 128 + 1); mp_div(&a, &d, &b, &e); mp_div_3(&a, &c, &r2); if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) { printf("\n\nmp_div_3 => Failure\n"); } } printf("\n\nPassed div_3 testing\n"); /* test the DR reduction */ printf("testing mp_dr_reduce...\n"); for (cnt = 2; cnt < 32; cnt++) { printf("%d digit modulus\n", cnt); mp_grow(&a, cnt); mp_zero(&a); for (ix = 1; ix < cnt; ix++) { a.dp[ix] = MP_MASK; } a.used = cnt; a.dp[0] = 3; mp_rand(&b, cnt - 1); mp_copy(&b, &c); rr = 0; do { if (!(rr & 127)) { printf("%9lu\r", rr); fflush(stdout); } mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_copy(&b, &c); mp_mod(&b, &a, &b); mp_dr_reduce(&c, &a, (((mp_digit)1)<<DIGIT_BIT)-a.dp[0]); if (mp_cmp(&b, &c) != MP_EQ) { printf("Failed on trial %lu\n", rr); exit(-1); } } while (++rr < 500); printf("Passed DR test for %d digits\n", cnt); } #endif div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n = sub_d_n= 0; /* force KARA and TOOM to enable despite cutoffs */ KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 110; TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 150; for (;;) { /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ switch (abs(rand()) % 7) { case 0: mp_clear(&a); mp_init(&a); break; case 1: mp_clear(&b); mp_init(&b); break; case 2: mp_clear(&c); mp_init(&c); break; case 3: mp_clear(&d); mp_init(&d); break; case 4: mp_clear(&e); mp_init(&e); break; case 5: mp_clear(&f); mp_init(&f); break; case 6: break; /* don't clear any */ } printf("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); fgets(cmd, 4095, stdin); cmd[strlen(cmd)-1] = 0; printf("%s ]\r",cmd); fflush(stdout); if (!strcmp(cmd, "mul2d")) { ++mul2d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_mul_2d(&a, rr, &a); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { printf("mul2d failed, rr == %d\n",rr); draw(&a); draw(&b); return 0; } } else if (!strcmp(cmd, "div2d")) { ++div2d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &rr); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_div_2d(&a, rr, &a, &e); a.sign = b.sign; if (a.used == b.used && a.used == 0) { a.sign = b.sign = MP_ZPOS; } if (mp_cmp(&a, &b) != MP_EQ) { printf("div2d failed, rr == %d\n",rr); draw(&a); draw(&b); return 0; } } else if (!strcmp(cmd, "add")) { ++add_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_add(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("add %lu failure!\n", add_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } /* test the sign/unsigned storage functions */ rr = mp_signed_bin_size(&c); mp_to_signed_bin(&c, (unsigned char *)cmd); memset(cmd+rr, rand()&255, sizeof(cmd)-rr); mp_read_signed_bin(&d, (unsigned char *)cmd, rr); if (mp_cmp(&c, &d) != MP_EQ) { printf("mp_signed_bin failure!\n"); draw(&c); draw(&d); return 0; } rr = mp_unsigned_bin_size(&c); mp_to_unsigned_bin(&c, (unsigned char *)cmd); memset(cmd+rr, rand()&255, sizeof(cmd)-rr); mp_read_unsigned_bin(&d, (unsigned char *)cmd, rr); if (mp_cmp_mag(&c, &d) != MP_EQ) { printf("mp_unsigned_bin failure!\n"); draw(&c); draw(&d); return 0; } } else if (!strcmp(cmd, "sub")) { ++sub_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_sub(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("sub %lu failure!\n", sub_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "mul")) { ++mul_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_mul(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("mul %lu failure!\n", mul_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "div")) { ++div_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); mp_div(&a, &b, &e, &f); if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), mp_cmp(&d, &f)); draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); draw(&f); return 0; } } else if (!strcmp(cmd, "sqr")) { ++sqr_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_copy(&a, &c); mp_sqr(&c, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sqr %lu failure!\n", sqr_n); draw(&a);draw(&b);draw(&c); return 0; } } else if (!strcmp(cmd, "gcd")) { ++gcd_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_gcd(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("gcd %lu failure!\n", gcd_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "lcm")) { ++lcm_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_lcm(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("lcm %lu failure!\n", lcm_n); draw(&a);draw(&b);draw(&c);draw(&d); return 0; } } else if (!strcmp(cmd, "expt")) { ++expt_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&d, buf, 64); mp_copy(&a, &e); mp_exptmod(&e, &b, &c, &e); if (mp_cmp(&d, &e) != MP_EQ) { printf("expt %lu failure!\n", expt_n); draw(&a);draw(&b);draw(&c);draw(&d); draw(&e); return 0; } } else if (!strcmp(cmd, "invmod")) { ++inv_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&c, buf, 64); mp_invmod(&a, &b, &d); mp_mulmod(&d,&a,&b,&e); if (mp_cmp_d(&e, 1) != MP_EQ) { printf("inv [wrong value from MPI?!] failure\n"); draw(&a);draw(&b);draw(&c);draw(&d); mp_gcd(&a, &b, &e); draw(&e); return 0; } } else if (!strcmp(cmd, "div2")) { ++div2_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_div_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); draw(&a); draw(&b); draw(&c); return 0; } } else if (!strcmp(cmd, "mul2")) { ++mul2_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_mul_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); draw(&a); draw(&b); draw(&c); return 0; } } else if (!strcmp(cmd, "add_d")) { ++add_d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &ix); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_add_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("add_d %lu failure\n", add_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return 0; } } else if (!strcmp(cmd, "sub_d")) { ++sub_d_n; fgets(buf, 4095, stdin); mp_read_radix(&a, buf, 64); fgets(buf, 4095, stdin); sscanf(buf, "%d", &ix); fgets(buf, 4095, stdin); mp_read_radix(&b, buf, 64); mp_sub_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sub_d %lu failure\n", sub_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return 0; } } } return 0; }
/** Sign a hash with DSA @param in The hash to sign @param inlen The length of the hash to sign @param r The "r" integer of the signature (caller must initialize with mp_init() first) @param s The "s" integer of the signature (caller must initialize with mp_init() first) @param prng An active PRNG state @param wprng The index of the PRNG desired @param key A private DSA key @return CRYPT_OK if successful */ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, void *r, void *s, prng_state *prng, int wprng, dsa_key *key) { void *k, *kinv, *tmp; unsigned char *buf; int err, qbits; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(key != NULL); if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* check group order size */ if (key->qord >= LTC_MDSA_MAX_GROUP) { return CRYPT_INVALID_ARG; } buf = XMALLOC(LTC_MDSA_MAX_GROUP); if (buf == NULL) { return CRYPT_MEM; } /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } qbits = mp_count_bits(key->q); retry: do { /* gen random k */ if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK) { goto error; } /* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */ if (mp_cmp_d(k, 0) != LTC_MP_GT || mp_cmp(k, key->q) != LTC_MP_LT) { goto retry; } /* test gcd */ if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(tmp, 1) != LTC_MP_EQ); /* now find 1/k mod q */ if ((err = mp_invmod(k, key->q, kinv)) != CRYPT_OK) { goto error; } /* now find r = g^k mod p mod q */ if ((err = mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK) { goto error; } if ((err = mp_mod(r, key->q, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { goto retry; } /* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/ inlen = MIN(inlen, (unsigned long)(key->qord)); /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(key->x, r, s)) != CRYPT_OK) { goto error; } if ((err = mp_add(s, tmp, s)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK) { goto error; } if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; error: mp_clear_multi(k, kinv, tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, LTC_MDSA_MAX_GROUP); #endif XFREE(buf); return err; }
int ecc_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, ecc_key *key) { ecc_key pubkey; void *r, *s, *e, *p; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* is this a private key? */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* get the hash and load it as a bignum into 'e' */ /* init the bignums */ if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != CRYPT_OK) { return err; } if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errnokey; } if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto errnokey; } /* make up a key and export the public copy */ for (;;) { if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) { goto errnokey; } /* find r = x1 mod n */ if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { ecc_free(&pubkey); } else { /* find s = (e + xr)/k */ if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/k */ if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */ if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mod(s, p, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */ ecc_free(&pubkey); if (mp_iszero(s) == LTC_MP_NO) { break; } } } /* store as SEQUENCE { r, s -- integer } */ err = der_encode_sequence_multi(out, outlen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL); goto errnokey; error: ecc_free(&pubkey); errnokey: mp_clear_multi(r, s, p, e, NULL); return err; }
int main(void) { unsigned rr; int cnt, ix; #if LTM_DEMO_TEST_VS_MTEST unsigned long expt_n, add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n; char* ret; #else unsigned long s, t; unsigned long long q, r; mp_digit mp; int i, n, err, should; #endif if (mp_init_multi(&a, &b, &c, &d, &e, &f, NULL)!= MP_OKAY) return EXIT_FAILURE; atexit(_cleanup); #if defined(LTM_DEMO_REAL_RAND) if (!fd_urandom) { fd_urandom = fopen("/dev/urandom", "r"); if (!fd_urandom) { #if !defined(_WIN32) fprintf(stderr, "\ncould not open /dev/urandom\n"); #endif } } #endif srand(LTM_DEMO_RAND_SEED); #ifdef MP_8BIT printf("Digit size 8 Bit \n"); #endif #ifdef MP_16BIT printf("Digit size 16 Bit \n"); #endif #ifdef MP_32BIT printf("Digit size 32 Bit \n"); #endif #ifdef MP_64BIT printf("Digit size 64 Bit \n"); #endif printf("Size of mp_digit: %u\n", (unsigned int)sizeof(mp_digit)); printf("Size of mp_word: %u\n", (unsigned int)sizeof(mp_word)); printf("DIGIT_BIT: %d\n", DIGIT_BIT); printf("MP_PREC: %d\n", MP_PREC); #if LTM_DEMO_TEST_VS_MTEST == 0 // trivial stuff // a: 0->5 mp_set_int(&a, 5); // a: 5-> b: -5 mp_neg(&a, &b); if (mp_cmp(&a, &b) != MP_GT) { return EXIT_FAILURE; } if (mp_cmp(&b, &a) != MP_LT) { return EXIT_FAILURE; } // a: 5-> a: -5 mp_neg(&a, &a); if (mp_cmp(&b, &a) != MP_EQ) { return EXIT_FAILURE; } // a: -5-> b: 5 mp_abs(&a, &b); if (mp_isneg(&b) != MP_NO) { return EXIT_FAILURE; } // a: -5-> b: -4 mp_add_d(&a, 1, &b); if (mp_isneg(&b) != MP_YES) { return EXIT_FAILURE; } if (mp_get_int(&b) != 4) { return EXIT_FAILURE; } // a: -5-> b: 1 mp_add_d(&a, 6, &b); if (mp_get_int(&b) != 1) { return EXIT_FAILURE; } // a: -5-> a: 1 mp_add_d(&a, 6, &a); if (mp_get_int(&a) != 1) { return EXIT_FAILURE; } mp_zero(&a); // a: 0-> a: 6 mp_add_d(&a, 6, &a); if (mp_get_int(&a) != 6) { return EXIT_FAILURE; } mp_set_int(&a, 0); mp_set_int(&b, 1); if ((err = mp_jacobi(&a, &b, &i)) != MP_OKAY) { printf("Failed executing mp_jacobi(0 | 1) %s.\n", mp_error_to_string(err)); return EXIT_FAILURE; } if (i != 1) { printf("Failed trivial mp_jacobi(0 | 1) %d != 1\n", i); return EXIT_FAILURE; } for (cnt = 0; cnt < (int)(sizeof(jacobi)/sizeof(jacobi[0])); ++cnt) { mp_set_int(&b, jacobi[cnt].n); /* only test positive values of a */ for (n = -5; n <= 10; ++n) { mp_set_int(&a, abs(n)); should = MP_OKAY; if (n < 0) { mp_neg(&a, &a); /* Until #44 is fixed the negative a's must fail */ should = MP_VAL; } if ((err = mp_jacobi(&a, &b, &i)) != should) { printf("Failed executing mp_jacobi(%d | %lu) %s.\n", n, jacobi[cnt].n, mp_error_to_string(err)); return EXIT_FAILURE; } if (err == MP_OKAY && i != jacobi[cnt].c[n + 5]) { printf("Failed trivial mp_jacobi(%d | %lu) %d != %d\n", n, jacobi[cnt].n, i, jacobi[cnt].c[n + 5]); return EXIT_FAILURE; } } } // test mp_get_int printf("\n\nTesting: mp_get_int"); for (i = 0; i < 1000; ++i) { t = ((unsigned long) rand () * rand () + 1) & 0xFFFFFFFF; mp_set_int (&a, t); if (t != mp_get_int (&a)) { printf ("\nmp_get_int() bad result!"); return EXIT_FAILURE; } } mp_set_int(&a, 0); if (mp_get_int(&a) != 0) { printf("\nmp_get_int() bad result!"); return EXIT_FAILURE; } mp_set_int(&a, 0xffffffff); if (mp_get_int(&a) != 0xffffffff) { printf("\nmp_get_int() bad result!"); return EXIT_FAILURE; } printf("\n\nTesting: mp_get_long\n"); for (i = 0; i < (int)(sizeof(unsigned long)*CHAR_BIT) - 1; ++i) { t = (1ULL << (i+1)) - 1; if (!t) t = -1; printf(" t = 0x%lx i = %d\r", t, i); do { if (mp_set_long(&a, t) != MP_OKAY) { printf("\nmp_set_long() error!"); return EXIT_FAILURE; } s = mp_get_long(&a); if (s != t) { printf("\nmp_get_long() bad result! 0x%lx != 0x%lx", s, t); return EXIT_FAILURE; } t <<= 1; } while(t); } printf("\n\nTesting: mp_get_long_long\n"); for (i = 0; i < (int)(sizeof(unsigned long long)*CHAR_BIT) - 1; ++i) { r = (1ULL << (i+1)) - 1; if (!r) r = -1; printf(" r = 0x%llx i = %d\r", r, i); do { if (mp_set_long_long(&a, r) != MP_OKAY) { printf("\nmp_set_long_long() error!"); return EXIT_FAILURE; } q = mp_get_long_long(&a); if (q != r) { printf("\nmp_get_long_long() bad result! 0x%llx != 0x%llx", q, r); return EXIT_FAILURE; } r <<= 1; } while(r); } // test mp_sqrt printf("\n\nTesting: mp_sqrt\n"); for (i = 0; i < 1000; ++i) { printf ("%6d\r", i); fflush (stdout); n = (rand () & 15) + 1; mp_rand (&a, n); if (mp_sqrt (&a, &b) != MP_OKAY) { printf ("\nmp_sqrt() error!"); return EXIT_FAILURE; } mp_n_root_ex (&a, 2, &c, 0); mp_n_root_ex (&a, 2, &d, 1); if (mp_cmp_mag (&c, &d) != MP_EQ) { printf ("\nmp_n_root_ex() bad result!"); return EXIT_FAILURE; } if (mp_cmp_mag (&b, &c) != MP_EQ) { printf ("mp_sqrt() bad result!\n"); return EXIT_FAILURE; } } printf("\n\nTesting: mp_is_square\n"); for (i = 0; i < 1000; ++i) { printf ("%6d\r", i); fflush (stdout); /* test mp_is_square false negatives */ n = (rand () & 7) + 1; mp_rand (&a, n); mp_sqr (&a, &a); if (mp_is_square (&a, &n) != MP_OKAY) { printf ("\nfn:mp_is_square() error!"); return EXIT_FAILURE; } if (n == 0) { printf ("\nfn:mp_is_square() bad result!"); return EXIT_FAILURE; } /* test for false positives */ mp_add_d (&a, 1, &a); if (mp_is_square (&a, &n) != MP_OKAY) { printf ("\nfp:mp_is_square() error!"); return EXIT_FAILURE; } if (n == 1) { printf ("\nfp:mp_is_square() bad result!"); return EXIT_FAILURE; } } printf("\n\n"); // r^2 = n (mod p) for (i = 0; i < (int)(sizeof(sqrtmod_prime)/sizeof(sqrtmod_prime[0])); ++i) { mp_set_int(&a, sqrtmod_prime[i].p); mp_set_int(&b, sqrtmod_prime[i].n); if (mp_sqrtmod_prime(&b, &a, &c) != MP_OKAY) { printf("Failed executing %d. mp_sqrtmod_prime\n", (i+1)); return EXIT_FAILURE; } if (mp_cmp_d(&c, sqrtmod_prime[i].r) != MP_EQ) { printf("Failed %d. trivial mp_sqrtmod_prime\n", (i+1)); ndraw(&c, "r"); return EXIT_FAILURE; } } /* test for size */ for (ix = 10; ix < 128; ix++) { printf ("Testing (not safe-prime): %9d bits \r", ix); fflush (stdout); err = mp_prime_random_ex (&a, 8, ix, (rand () & 1) ? 0 : LTM_PRIME_2MSB_ON, myrng, NULL); if (err != MP_OKAY) { printf ("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits (&a) != ix) { printf ("Prime is %d not %d bits!!!\n", mp_count_bits (&a), ix); return EXIT_FAILURE; } } printf("\n"); for (ix = 16; ix < 128; ix++) { printf ("Testing ( safe-prime): %9d bits \r", ix); fflush (stdout); err = mp_prime_random_ex ( &a, 8, ix, ((rand () & 1) ? 0 : LTM_PRIME_2MSB_ON) | LTM_PRIME_SAFE, myrng, NULL); if (err != MP_OKAY) { printf ("failed with err code %d\n", err); return EXIT_FAILURE; } if (mp_count_bits (&a) != ix) { printf ("Prime is %d not %d bits!!!\n", mp_count_bits (&a), ix); return EXIT_FAILURE; } /* let's see if it's really a safe prime */ mp_sub_d (&a, 1, &a); mp_div_2 (&a, &a); mp_prime_is_prime (&a, 8, &cnt); if (cnt != MP_YES) { printf ("sub is not prime!\n"); return EXIT_FAILURE; } } printf("\n\n"); // test montgomery printf("Testing: montgomery...\n"); for (i = 1; i <= 10; i++) { if (i == 10) i = 1000; printf(" digit size: %2d\r", i); fflush(stdout); for (n = 0; n < 1000; n++) { mp_rand(&a, i); a.dp[0] |= 1; // let's see if R is right mp_montgomery_calc_normalization(&b, &a); mp_montgomery_setup(&a, &mp); // now test a random reduction for (ix = 0; ix < 100; ix++) { mp_rand(&c, 1 + abs(rand()) % (2*i)); mp_copy(&c, &d); mp_copy(&c, &e); mp_mod(&d, &a, &d); mp_montgomery_reduce(&c, &a, mp); mp_mulmod(&c, &b, &a, &c); if (mp_cmp(&c, &d) != MP_EQ) { printf("d = e mod a, c = e MOD a\n"); mp_todecimal(&a, buf); printf("a = %s\n", buf); mp_todecimal(&e, buf); printf("e = %s\n", buf); mp_todecimal(&d, buf); printf("d = %s\n", buf); mp_todecimal(&c, buf); printf("c = %s\n", buf); printf("compare no compare!\n"); return EXIT_FAILURE; } /* only one big montgomery reduction */ if (i > 10) { n = 1000; ix = 100; } } } } printf("\n\n"); mp_read_radix(&a, "123456", 10); mp_toradix_n(&a, buf, 10, 3); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 4); printf("a == %s\n", buf); mp_toradix_n(&a, buf, 10, 30); printf("a == %s\n", buf); #if 0 for (;;) { fgets(buf, sizeof(buf), stdin); mp_read_radix(&a, buf, 10); mp_prime_next_prime(&a, 5, 1); mp_toradix(&a, buf, 10); printf("%s, %lu\n", buf, a.dp[0] & 3); } #endif /* test mp_cnt_lsb */ printf("\n\nTesting: mp_cnt_lsb"); mp_set(&a, 1); for (ix = 0; ix < 1024; ix++) { if (mp_cnt_lsb (&a) != ix) { printf ("Failed at %d, %d\n", ix, mp_cnt_lsb (&a)); return EXIT_FAILURE; } mp_mul_2 (&a, &a); } /* test mp_reduce_2k */ printf("\n\nTesting: mp_reduce_2k\n"); for (cnt = 3; cnt <= 128; ++cnt) { mp_digit tmp; mp_2expt (&a, cnt); mp_sub_d (&a, 2, &a); /* a = 2**cnt - 2 */ printf ("\r %4d bits", cnt); printf ("(%d)", mp_reduce_is_2k (&a)); mp_reduce_2k_setup (&a, &tmp); printf ("(%lu)", (unsigned long) tmp); for (ix = 0; ix < 1000; ix++) { if (!(ix & 127)) { printf ("."); fflush (stdout); } mp_rand (&b, (cnt / DIGIT_BIT + 1) * 2); mp_copy (&c, &b); mp_mod (&c, &a, &c); mp_reduce_2k (&b, &a, 2); if (mp_cmp (&c, &b)) { printf ("FAILED\n"); return EXIT_FAILURE; } } } /* test mp_div_3 */ printf("\n\nTesting: mp_div_3...\n"); mp_set(&d, 3); for (cnt = 0; cnt < 10000;) { mp_digit r2; if (!(++cnt & 127)) { printf("%9d\r", cnt); fflush(stdout); } mp_rand(&a, abs(rand()) % 128 + 1); mp_div(&a, &d, &b, &e); mp_div_3(&a, &c, &r2); if (mp_cmp(&b, &c) || mp_cmp_d(&e, r2)) { printf("\nmp_div_3 => Failure\n"); } } printf("\nPassed div_3 testing"); /* test the DR reduction */ printf("\n\nTesting: mp_dr_reduce...\n"); for (cnt = 2; cnt < 32; cnt++) { printf ("\r%d digit modulus", cnt); mp_grow (&a, cnt); mp_zero (&a); for (ix = 1; ix < cnt; ix++) { a.dp[ix] = MP_MASK; } a.used = cnt; a.dp[0] = 3; mp_rand (&b, cnt - 1); mp_copy (&b, &c); rr = 0; do { if (!(rr & 127)) { printf ("."); fflush (stdout); } mp_sqr (&b, &b); mp_add_d (&b, 1, &b); mp_copy (&b, &c); mp_mod (&b, &a, &b); mp_dr_setup(&a, &mp), mp_dr_reduce (&c, &a, mp); if (mp_cmp (&b, &c) != MP_EQ) { printf ("Failed on trial %u\n", rr); return EXIT_FAILURE; } } while (++rr < 500); printf (" passed"); fflush (stdout); } #if LTM_DEMO_TEST_REDUCE_2K_L /* test the mp_reduce_2k_l code */ #if LTM_DEMO_TEST_REDUCE_2K_L == 1 /* first load P with 2^1024 - 0x2A434 B9FDEC95 D8F9D550 FFFFFFFF FFFFFFFF */ mp_2expt(&a, 1024); mp_read_radix(&b, "2A434B9FDEC95D8F9D550FFFFFFFFFFFFFFFF", 16); mp_sub(&a, &b, &a); #elif LTM_DEMO_TEST_REDUCE_2K_L == 2 /* p = 2^2048 - 0x1 00000000 00000000 00000000 00000000 4945DDBF 8EA2A91D 5776399B B83E188F */ mp_2expt(&a, 2048); mp_read_radix(&b, "1000000000000000000000000000000004945DDBF8EA2A91D5776399BB83E188F", 16); mp_sub(&a, &b, &a); #else #error oops #endif mp_todecimal(&a, buf); printf("\n\np==%s\n", buf); /* now mp_reduce_is_2k_l() should return */ if (mp_reduce_is_2k_l(&a) != 1) { printf("mp_reduce_is_2k_l() return 0, should be 1\n"); return EXIT_FAILURE; } mp_reduce_2k_setup_l(&a, &d); /* now do a million square+1 to see if it varies */ mp_rand(&b, 64); mp_mod(&b, &a, &b); mp_copy(&b, &c); printf("Testing: mp_reduce_2k_l..."); fflush(stdout); for (cnt = 0; cnt < (int)(1UL << 20); cnt++) { mp_sqr(&b, &b); mp_add_d(&b, 1, &b); mp_reduce_2k_l(&b, &a, &d); mp_sqr(&c, &c); mp_add_d(&c, 1, &c); mp_mod(&c, &a, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("mp_reduce_2k_l() failed at step %d\n", cnt); mp_tohex(&b, buf); printf("b == %s\n", buf); mp_tohex(&c, buf); printf("c == %s\n", buf); return EXIT_FAILURE; } } printf("...Passed\n"); #endif /* LTM_DEMO_TEST_REDUCE_2K_L */ #else div2_n = mul2_n = inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = cnt = add_d_n = sub_d_n = 0; /* force KARA and TOOM to enable despite cutoffs */ KARATSUBA_SQR_CUTOFF = KARATSUBA_MUL_CUTOFF = 8; TOOM_SQR_CUTOFF = TOOM_MUL_CUTOFF = 16; for (;;) { /* randomly clear and re-init one variable, this has the affect of triming the alloc space */ switch (abs(rand()) % 7) { case 0: mp_clear(&a); mp_init(&a); break; case 1: mp_clear(&b); mp_init(&b); break; case 2: mp_clear(&c); mp_init(&c); break; case 3: mp_clear(&d); mp_init(&d); break; case 4: mp_clear(&e); mp_init(&e); break; case 5: mp_clear(&f); mp_init(&f); break; case 6: break; /* don't clear any */ } printf ("%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu/%4lu ", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, div2_n, mul2_n, add_d_n, sub_d_n); ret=fgets(cmd, 4095, stdin); if(!ret){_panic(__LINE__);} cmd[strlen(cmd) - 1] = 0; printf("%-6s ]\r", cmd); fflush(stdout); if (!strcmp(cmd, "mul2d")) { ++mul2d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &rr); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_mul_2d(&a, rr, &a); a.sign = b.sign; if (mp_cmp(&a, &b) != MP_EQ) { printf("mul2d failed, rr == %d\n", rr); draw(&a); draw(&b); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div2d")) { ++div2d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &rr); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_div_2d(&a, rr, &a, &e); a.sign = b.sign; if (a.used == b.used && a.used == 0) { a.sign = b.sign = MP_ZPOS; } if (mp_cmp(&a, &b) != MP_EQ) { printf("div2d failed, rr == %d\n", rr); draw(&a); draw(&b); return EXIT_FAILURE; } } else if (!strcmp(cmd, "add")) { ++add_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_add(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("add %lu failure!\n", add_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } /* test the sign/unsigned storage functions */ rr = mp_signed_bin_size(&c); mp_to_signed_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_signed_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp(&c, &d) != MP_EQ) { printf("mp_signed_bin failure!\n"); draw(&c); draw(&d); return EXIT_FAILURE; } rr = mp_unsigned_bin_size(&c); mp_to_unsigned_bin(&c, (unsigned char *) cmd); memset(cmd + rr, rand() & 255, sizeof(cmd) - rr); mp_read_unsigned_bin(&d, (unsigned char *) cmd, rr); if (mp_cmp_mag(&c, &d) != MP_EQ) { printf("mp_unsigned_bin failure!\n"); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sub")) { ++sub_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_sub(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("sub %lu failure!\n", sub_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "mul")) { ++mul_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_mul(&d, &b, &d); if (mp_cmp(&c, &d) != MP_EQ) { printf("mul %lu failure!\n", mul_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div")) { ++div_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&d, buf, 64); mp_div(&a, &b, &e, &f); if (mp_cmp(&c, &e) != MP_EQ || mp_cmp(&d, &f) != MP_EQ) { printf("div %lu %d, %d, failure!\n", div_n, mp_cmp(&c, &e), mp_cmp(&d, &f)); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); draw(&f); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sqr")) { ++sqr_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_copy(&a, &c); mp_sqr(&c, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sqr %lu failure!\n", sqr_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "gcd")) { ++gcd_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_gcd(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("gcd %lu failure!\n", gcd_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "lcm")) { ++lcm_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_copy(&a, &d); mp_lcm(&d, &b, &d); d.sign = c.sign; if (mp_cmp(&c, &d) != MP_EQ) { printf("lcm %lu failure!\n", lcm_n); draw(&a); draw(&b); draw(&c); draw(&d); return EXIT_FAILURE; } } else if (!strcmp(cmd, "expt")) { ++expt_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&d, buf, 64); mp_copy(&a, &e); mp_exptmod(&e, &b, &c, &e); if (mp_cmp(&d, &e) != MP_EQ) { printf("expt %lu failure!\n", expt_n); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); return EXIT_FAILURE; } } else if (!strcmp(cmd, "invmod")) { ++inv_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&c, buf, 64); mp_invmod(&a, &b, &d); mp_mulmod(&d, &a, &b, &e); if (mp_cmp_d(&e, 1) != MP_EQ) { printf("inv [wrong value from MPI?!] failure\n"); draw(&a); draw(&b); draw(&c); draw(&d); draw(&e); mp_gcd(&a, &b, &e); draw(&e); return EXIT_FAILURE; } } else if (!strcmp(cmd, "div2")) { ++div2_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_div_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("div_2 %lu failure\n", div2_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "mul2")) { ++mul2_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_mul_2(&a, &c); if (mp_cmp(&c, &b) != MP_EQ) { printf("mul_2 %lu failure\n", mul2_n); draw(&a); draw(&b); draw(&c); return EXIT_FAILURE; } } else if (!strcmp(cmd, "add_d")) { ++add_d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &ix); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_add_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("add_d %lu failure\n", add_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return EXIT_FAILURE; } } else if (!strcmp(cmd, "sub_d")) { ++sub_d_n; ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&a, buf, 64); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} sscanf(buf, "%d", &ix); ret=fgets(buf, 4095, stdin); if(!ret){_panic(__LINE__);} mp_read_radix(&b, buf, 64); mp_sub_d(&a, ix, &c); if (mp_cmp(&b, &c) != MP_EQ) { printf("sub_d %lu failure\n", sub_d_n); draw(&a); draw(&b); draw(&c); printf("d == %d\n", ix); return EXIT_FAILURE; } } else if (!strcmp(cmd, "exit")) { printf("\nokay, exiting now\n"); break; } } #endif return 0; }
int mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode) { mp_int M[TAB_SIZE], res; mp_digit buf, mp; int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; /* use a pointer to the reduction algorithm. This allows us to use * one of many reduction algorithms without modding the guts of * the code with if statements everywhere. */ int (*redux)(mp_int *x, const mp_int *n, mp_digit rho); /* find window size */ x = mp_count_bits(X); if (x <= 7) { winsize = 2; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { winsize = 4; } else if (x <= 450) { winsize = 5; } else if (x <= 1303) { winsize = 6; } else if (x <= 3529) { winsize = 7; } else { winsize = 8; } #ifdef MP_LOW_MEM if (winsize > 5) { winsize = 5; } #endif /* init M array */ /* init first cell */ if ((err = mp_init_size(&M[1], P->alloc)) != MP_OKAY) { return err; } /* now init the second half of the array */ for (x = 1<<(winsize-1); x < (1 << winsize); x++) { if ((err = mp_init_size(&M[x], P->alloc)) != MP_OKAY) { for (y = 1<<(winsize-1); y < x; y++) { mp_clear(&M[y]); } mp_clear(&M[1]); return err; } } /* determine and setup reduction code */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_SETUP_C /* now setup montgomery */ if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) { goto LBL_M; } #else err = MP_VAL; goto LBL_M; #endif /* automatically pick the comba one if available (saves quite a few calls/ifs) */ #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C if ((((P->used * 2) + 1) < (int)MP_WARRAY) && (P->used < (1 << ((CHAR_BIT * sizeof(mp_word)) - (2 * DIGIT_BIT))))) { redux = fast_mp_montgomery_reduce; } else #endif { #ifdef BN_MP_MONTGOMERY_REDUCE_C /* use slower baseline Montgomery method */ redux = mp_montgomery_reduce; #else err = MP_VAL; goto LBL_M; #endif } } else if (redmode == 1) { #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) /* setup DR reduction for moduli of the form B**k - b */ mp_dr_setup(P, &mp); redux = mp_dr_reduce; #else err = MP_VAL; goto LBL_M; #endif } else { #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) /* setup DR reduction for moduli of the form 2**k - b */ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { goto LBL_M; } redux = mp_reduce_2k; #else err = MP_VAL; goto LBL_M; #endif } /* setup result */ if ((err = mp_init_size(&res, P->alloc)) != MP_OKAY) { goto LBL_M; } /* create M table * * * The first half of the table is not computed though accept for M[0] and M[1] */ if (redmode == 0) { #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C /* now we need R mod m */ if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) { goto LBL_RES; } /* now set M[1] to G * R mod m */ if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) { goto LBL_RES; } #else err = MP_VAL; goto LBL_RES; #endif } else { mp_set(&res, 1uL); if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { goto LBL_RES; } } /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ if ((err = mp_copy(&M[1], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } for (x = 0; x < (winsize - 1); x++) { if ((err = mp_sqr(&M[(size_t)1 << (winsize - 1)], &M[(size_t)1 << (winsize - 1)])) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&M[(size_t)1 << (winsize - 1)], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* create upper table */ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { if ((err = mp_mul(&M[x - 1], &M[1], &M[x])) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&M[x], P, mp)) != MP_OKAY) { goto LBL_RES; } } /* set initial mode and bit cnt */ mode = 0; bitcnt = 1; buf = 0; digidx = X->used - 1; bitcpy = 0; bitbuf = 0; for (;;) { /* grab next digit as required */ if (--bitcnt == 0) { /* if digidx == -1 we are out of digits so break */ if (digidx == -1) { break; } /* read next digit and reset bitcnt */ buf = X->dp[digidx--]; bitcnt = (int)DIGIT_BIT; } /* grab the next msb from the exponent */ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; buf <<= (mp_digit)1; /* if the bit is zero and mode == 0 then we ignore it * These represent the leading zero bits before the first 1 bit * in the exponent. Technically this opt is not required but it * does lower the # of trivial squaring/reductions used */ if ((mode == 0) && (y == 0)) { continue; } /* if the bit is zero and mode == 1 then we square */ if ((mode == 1) && (y == 0)) { if ((err = mp_sqr(&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } continue; } /* else we add it to the window */ bitbuf |= (y << (winsize - ++bitcpy)); mode = 2; if (bitcpy == winsize) { /* ok window is filled so square as required and multiply */ /* square first */ for (x = 0; x < winsize; x++) { if ((err = mp_sqr(&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* then multiply */ if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* empty window and reset */ bitcpy = 0; bitbuf = 0; mode = 1; } } /* if bits remain then square/multiply */ if ((mode == 2) && (bitcpy > 0)) { /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr(&res, &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } /* get next bit of the window */ bitbuf <<= 1; if ((bitbuf & (1 << winsize)) != 0) { /* then multiply */ if ((err = mp_mul(&res, &M[1], &res)) != MP_OKAY) { goto LBL_RES; } if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } } } if (redmode == 0) { /* fixup result if Montgomery reduction is used * recall that any value in a Montgomery system is * actually multiplied by R mod n. So we have * to reduce one more time to cancel out the factor * of R. */ if ((err = redux(&res, P, mp)) != MP_OKAY) { goto LBL_RES; } } /* swap res with Y */ mp_exch(&res, Y); err = MP_OKAY; LBL_RES: mp_clear(&res); LBL_M: mp_clear(&M[1]); for (x = 1<<(winsize-1); x < (1 << winsize); x++) { mp_clear(&M[x]); } return err; }
/* Store non-zero to ret if arg is square, and zero if not */ int mp_is_square(mp_int *arg,int *ret) { int res; mp_digit c; mp_int t; unsigned long r; /* Default to Non-square :) */ *ret = MP_NO; if (arg->sign == MP_NEG) { return MP_VAL; } /* digits used? (TSD) */ if (arg->used == 0) { return MP_OKAY; } /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */ if (rem_128[127 & DIGIT(arg,0)] == 1) { return MP_OKAY; } /* Next check mod 105 (3*5*7) */ if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) { return res; } if (rem_105[c] == 1) { return MP_OKAY; } if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) { return res; } if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) { goto ERR; } r = mp_get_int(&t); /* Check for other prime modules, note it's not an ERROR but we must * free "t" so the easiest way is to goto ERR. We know that res * is already equal to MP_OKAY from the mp_mod call */ if ( (1L<<(r%11)) & 0x5C4L ) goto ERR; if ( (1L<<(r%13)) & 0x9E4L ) goto ERR; if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR; if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR; if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR; if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR; if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR; /* Final check - is sqr(sqrt(arg)) == arg ? */ if ((res = mp_sqrt(arg,&t)) != MP_OKAY) { goto ERR; } if ((res = mp_sqr(&t,&t)) != MP_OKAY) { goto ERR; } *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO; ERR:mp_clear(&t); return res; }
int rsa_make_key(int size, long e, rsa_key *key) { mp_int p, q, tmp1, tmp2, tmp3; int err; if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) { return CRYPT_INVALID_KEYSIZE; } if ((e < 3) || ((e & 1) == 0)) { return CRYPT_INVALID_ARG; } if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); } /* make primes p and q (optimization provided by Wayne Scott) */ if ((err = mp_set_int(&tmp3, e)) != MP_OKAY) { goto error; /* tmp3 = e */ } /* make prime "p" */ do { if ((err = rand_prime(&p, size*4)) != CRYPT_OK) { goto done; } if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error; /* tmp1 = p-1 */ } if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; /* tmp2 = gcd(p-1, e) */ } } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides p-1 */ /* make prime "q" */ do { if ((err = rand_prime(&q, size*4)) != CRYPT_OK) { goto done; } if ((err = mp_sub_d(&q, 1, &tmp1)) != MP_OKAY) { goto error; /* tmp1 = q-1 */ } if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; /* tmp2 = gcd(q-1, e) */ } } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides q-1 */ /* tmp1 = lcm(p-1, q-1) */ if ((err = mp_sub_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; /* tmp2 = p-1 */ } /* tmp1 = q-1 (previous do/while loop) */ if ((err = mp_lcm(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto error; /* tmp1 = lcm(p-1, q-1) */ } /* make key */ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != MP_OKAY) { goto error; } if ((err = mp_set_int(&key->e, e)) != MP_OKAY) { goto error2; /* key->e = e */ } if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; /* key->d = 1/e mod lcm(p-1,q-1) */ } if ((err = mp_mul(&p, &q, &key->N)) != MP_OKAY) { goto error2; /* key->N = pq */ } /* optimize for CRT now */ /* find d mod q-1 and d mod p-1 */ if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; /* tmp1 = q-1 */ } if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; /* tmp2 = p-1 */ } if ((err = mp_mod(&key->d, &tmp1, &key->dP)) != MP_OKAY) { goto error2; /* dP = d mod p-1 */ } if ((err = mp_mod(&key->d, &tmp2, &key->dQ)) != MP_OKAY) { goto error2; /* dQ = d mod q-1 */ } if ((err = mp_invmod(&q, &p, &key->qP)) != MP_OKAY) { goto error2; /* qP = 1/q mod p */ } if ((err = mp_copy(&p, &key->p)) != MP_OKAY) { goto error2; } if ((err = mp_copy(&q, &key->q)) != MP_OKAY) { goto error2; } /* shrink ram required */ if ((err = mp_shrink(&key->e)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->d)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->N)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->dQ)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->dP)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->qP)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error2; } if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error2; } /* set key type (in this case it's CRT optimized) */ key->type = PK_PRIVATE; /* return ok and free temps */ err = CRYPT_OK; goto done; error2: mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL); error: err = mpi_to_ltc_error(err); done: mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL); return err; }
int pb_sub(pb_poly *a, pb_poly *b, pb_poly *c) { int neg, err, x, y, z, characteristic; pb_poly *tmp; /* grow c to be the max size */ y = MAX(a->used, b->used); if (c->alloc < y) { if ((err = pb_grow(c, y)) != MP_OKAY) { return err; } } /* do we need to concern char */ characteristic = mp_iszero(&(c->characteristic)); /* sub the terms */ z = MIN(a->used, b->used); for (x = 0; x < z; x++) { if ((err = mp_sub(&(a->terms[x]), &(b->terms[x]), &(c->terms[x]))) != MP_OKAY) { return err; } if (characteristic == MP_NO) { if ((err = mp_mod(&(c->terms[x]), &(c->characteristic), &(c->terms[x]))) != MP_OKAY) { return err; } } } /* excess digits? */ if (y != z) { if (a->used == y) { tmp = a; neg = 0; } else { tmp = b; neg = 1; } for (x = z; x < y; x++) { if (characteristic == MP_NO) { if ((err = mp_mod(&(tmp->terms[x]), &(c->characteristic), &(c->terms[x]))) != MP_OKAY) { return err; } if (neg) { if ((err = mp_sub(&(c->characteristic), &(c->terms[x]), &(c->terms[x]))) != MP_OKAY) { return err; } } } else { if (neg) { if ((err = mp_neg(&(tmp->terms[x]), &(c->terms[x]))) != MP_OKAY) { return err; } } else { if ((err = mp_copy(&(tmp->terms[x]), &(c->terms[x]))) != MP_OKAY) { return err; } } } } } /* zero excess */ for (x = y; x < c->used; x++) { mp_zero(&(c->terms[x])); } c->used = y; pb_clamp(c); return MP_OKAY; }
/* hac 14.61, pp608 */ int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) { mp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if (b->sign == MP_NEG || mp_iszero(b) == 1) { return MP_VAL; } /* init temps */ if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { return res; } /* x = a, y = b */ if ((res = mp_mod(a, b, &x)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (b, &y)) != MP_OKAY) { goto LBL_ERR; } /* 2. [modified] if x,y are both even then return an error! */ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { res = MP_VAL; goto LBL_ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { goto LBL_ERR; } mp_set (&A, 1); mp_set (&D, 1); top: /* 4. while u is even do */ while (mp_iseven (&u) == 1) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto LBL_ERR; } /* 4.2 if A or B is odd then */ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { /* A = (A+y)/2, B = (B-x)/2 */ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto LBL_ERR; } } /* A = A/2, B = B/2 */ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { goto LBL_ERR; } } /* 5. while v is even do */ while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto LBL_ERR; } /* 5.2 if C or D is odd then */ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { /* C = (C+y)/2, D = (D-x)/2 */ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto LBL_ERR; } } /* C = C/2, D = D/2 */ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { goto LBL_ERR; } } /* 6. if u >= v then */ if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, A = A - C, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { goto LBL_ERR; } } else { /* v - v - u, C = C - A, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { goto LBL_ERR; } } /* if not zero goto step 4 */ if (mp_iszero (&u) == 0) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; goto LBL_ERR; } /* if its too low */ while (mp_cmp_d(&C, 0) == MP_LT) { if ((res = mp_add(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* too big */ while (mp_cmp_mag(&C, b) != MP_LT) { if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* C is now the inverse */ mp_exch (&C, c); res = MP_OKAY; LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); return res; }
/* Computes the ECDSA signature (a concatenation of two values r and s) * on the digest using the given key and the random value kb (used in * computing s). */ SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, const SECItem *digest, const unsigned char *kb, const int kblen) { SECStatus rv = SECFailure; #ifdef NSS_ENABLE_ECC mp_int x1; mp_int d, k; /* private key, random integer */ mp_int r, s; /* tuple (r, s) is the signature */ mp_int n; mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem kGpoint = { siBuffer, NULL, 0}; int flen = 0; /* length in bytes of the field size */ unsigned olen; /* length in bytes of the base point order */ unsigned obits; /* length in bits of the base point order */ #if EC_DEBUG char mpstr[256]; #endif /* Initialize MPI integers. */ /* must happen before the first potential call to cleanup */ MP_DIGITS(&x1) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&k) = 0; MP_DIGITS(&r) = 0; MP_DIGITS(&s) = 0; MP_DIGITS(&n) = 0; /* Check args */ if (!key || !signature || !digest || !kb || (kblen < 0)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto cleanup; } ecParams = &(key->ecParams); flen = (ecParams->fieldID.size + 7) >> 3; olen = ecParams->order.len; if (signature->data == NULL) { /* a call to get the signature length only */ goto finish; } if (signature->len < 2*olen) { PORT_SetError(SEC_ERROR_OUTPUT_LEN); goto cleanup; } CHECK_MPI_OK( mp_init(&x1) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&k) ); CHECK_MPI_OK( mp_init(&r) ); CHECK_MPI_OK( mp_init(&s) ); CHECK_MPI_OK( mp_init(&n) ); SECITEM_TO_MPINT( ecParams->order, &n ); SECITEM_TO_MPINT( key->privateValue, &d ); CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) ); /* Make sure k is in the interval [1, n-1] */ if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { #if EC_DEBUG printf("k is outside [1, n-1]\n"); mp_tohex(&k, mpstr); printf("k : %s \n", mpstr); mp_tohex(&n, mpstr); printf("n : %s \n", mpstr); #endif PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** We do not want timing information to leak the length of k, ** so we compute k*G using an equivalent scalar of fixed ** bit-length. ** Fix based on patch for ECDSA timing attack in the paper ** by Billy Bob Brumley and Nicola Tuveri at ** http://eprint.iacr.org/2011/232 ** ** How do we convert k to a value of a fixed bit-length? ** k starts off as an integer satisfying 0 <= k < n. Hence, ** n <= k+n < 2n, which means k+n has either the same number ** of bits as n or one more bit than n. If k+n has the same ** number of bits as n, the second addition ensures that the ** final value has exactly one more bit than n. Thus, we ** always end up with a value that exactly one more bit than n. */ CHECK_MPI_OK( mp_add(&k, &n, &k) ); if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) { CHECK_MPI_OK( mp_add(&k, &n, &k) ); } /* ** ANSI X9.62, Section 5.3.2, Step 2 ** ** Compute kG */ kGpoint.len = 2*flen + 1; kGpoint.data = PORT_Alloc(2*flen + 1); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) goto cleanup; /* ** ANSI X9.62, Section 5.3.3, Step 1 ** ** Extract the x co-ordinate of kG into x1 */ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, (mp_size) flen) ); /* ** ANSI X9.62, Section 5.3.3, Step 2 ** ** r = x1 mod n NOTE: n is the order of the curve */ CHECK_MPI_OK( mp_mod(&x1, &n, &r) ); /* ** ANSI X9.62, Section 5.3.3, Step 3 ** ** verify r != 0 */ if (mp_cmp_z(&r) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ANSI X9.62, Section 5.3.3, Step 4 ** ** s = (k**-1 * (HASH(M) + d*r)) mod n */ SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ /* In the definition of EC signing, digests are truncated * to the length of n in bits. * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); if (digest->len*8 > obits) { mpl_rsh(&s,&s,digest->len*8 - obits); } #if EC_DEBUG mp_todecimal(&n, mpstr); printf("n : %s (dec)\n", mpstr); mp_todecimal(&d, mpstr); printf("d : %s (dec)\n", mpstr); mp_tohex(&x1, mpstr); printf("x1: %s\n", mpstr); mp_todecimal(&s, mpstr); printf("digest: %s (decimal)\n", mpstr); mp_todecimal(&r, mpstr); printf("r : %s (dec)\n", mpstr); mp_tohex(&r, mpstr); printf("r : %s\n", mpstr); #endif CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */ CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */ CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */ CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */ #if EC_DEBUG mp_todecimal(&s, mpstr); printf("s : %s (dec)\n", mpstr); mp_tohex(&s, mpstr); printf("s : %s\n", mpstr); #endif /* ** ANSI X9.62, Section 5.3.3, Step 5 ** ** verify s != 0 */ if (mp_cmp_z(&s) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); goto cleanup; } /* ** ** Signature is tuple (r, s) */ CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) ); CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) ); finish: signature->len = 2*olen; rv = SECSuccess; err = MP_OKAY; cleanup: mp_clear(&x1); mp_clear(&d); mp_clear(&k); mp_clear(&r); mp_clear(&s); mp_clear(&n); if (kGpoint.data) { PORT_ZFree(kGpoint.data, 2*flen + 1); } if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } #if EC_DEBUG printf("ECDSA signing with seed %s\n", (rv == SECSuccess) ? "succeeded" : "failed"); #endif #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); #endif /* NSS_ENABLE_ECC */ return rv; }
static int ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) { mp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; int counter, ret, bitsp; if (bits < 789) return -1; bitsp = (bits + 1) / 2; ret = -1; mp_init_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); BN2mpz(&el, e); /* generate p and q so that p != q and bits(pq) ~ bits */ counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&p, bitsp), 0); CHECK(mp_find_prime(&p,128), MP_YES); mp_sub_d(&p, 1, &t1); mp_gcd(&t1, &el, &t2); } while(mp_cmp_d(&t2, 1) != 0); BN_GENCB_call(cb, 3, 0); counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&q, bits - bitsp), 0); CHECK(mp_find_prime(&q,128), MP_YES); if (mp_cmp(&p, &q) == 0) /* don't let p and q be the same */ continue; mp_sub_d(&q, 1, &t1); mp_gcd(&t1, &el, &t2); } while(mp_cmp_d(&t2, 1) != 0); /* make p > q */ if (mp_cmp(&p, &q) < 0) { mp_int c; c = p; p = q; q = c; } BN_GENCB_call(cb, 3, 1); /* calculate n, n = p * q */ mp_mul(&p, &q, &n); /* calculate d, d = 1/e mod (p - 1)(q - 1) */ mp_sub_d(&p, 1, &t1); mp_sub_d(&q, 1, &t2); mp_mul(&t1, &t2, &t3); mp_invmod(&el, &t3, &d); /* calculate dmp1 dmp1 = d mod (p-1) */ mp_mod(&d, &t1, &dmp1); /* calculate dmq1 dmq1 = d mod (q-1) */ mp_mod(&d, &t2, &dmq1); /* calculate iqmp iqmp = 1/q mod p */ mp_invmod(&q, &p, &iqmp); /* fill in RSA key */ rsa->e = mpz2BN(&el); rsa->p = mpz2BN(&p); rsa->q = mpz2BN(&q); rsa->n = mpz2BN(&n); rsa->d = mpz2BN(&d); rsa->dmp1 = mpz2BN(&dmp1); rsa->dmq1 = mpz2BN(&dmq1); rsa->iqmp = mpz2BN(&iqmp); ret = 1; out: mp_clear_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); return ret; }
/* ** Checks the signature on the given digest using the key provided. */ SECStatus ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, const SECItem *digest) { SECStatus rv = SECFailure; #ifdef NSS_ENABLE_ECC mp_int r_, s_; /* tuple (r', s') is received signature) */ mp_int c, u1, u2, v; /* intermediate values used in verification */ mp_int x1; mp_int n; mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem pointC = { siBuffer, NULL, 0 }; int slen; /* length in bytes of a half signature (r or s) */ int flen; /* length in bytes of the field size */ unsigned olen; /* length in bytes of the base point order */ unsigned obits; /* length in bits of the base point order */ #if EC_DEBUG char mpstr[256]; printf("ECDSA verification called\n"); #endif /* Initialize MPI integers. */ /* must happen before the first potential call to cleanup */ MP_DIGITS(&r_) = 0; MP_DIGITS(&s_) = 0; MP_DIGITS(&c) = 0; MP_DIGITS(&u1) = 0; MP_DIGITS(&u2) = 0; MP_DIGITS(&x1) = 0; MP_DIGITS(&v) = 0; MP_DIGITS(&n) = 0; /* Check args */ if (!key || !signature || !digest) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto cleanup; } ecParams = &(key->ecParams); flen = (ecParams->fieldID.size + 7) >> 3; olen = ecParams->order.len; if (signature->len == 0 || signature->len%2 != 0 || signature->len > 2*olen) { PORT_SetError(SEC_ERROR_INPUT_LEN); goto cleanup; } slen = signature->len/2; SECITEM_AllocItem(NULL, &pointC, 2*flen + 1); if (pointC.data == NULL) goto cleanup; CHECK_MPI_OK( mp_init(&r_) ); CHECK_MPI_OK( mp_init(&s_) ); CHECK_MPI_OK( mp_init(&c) ); CHECK_MPI_OK( mp_init(&u1) ); CHECK_MPI_OK( mp_init(&u2) ); CHECK_MPI_OK( mp_init(&x1) ); CHECK_MPI_OK( mp_init(&v) ); CHECK_MPI_OK( mp_init(&n) ); /* ** Convert received signature (r', s') into MPI integers. */ CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) ); CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) ); /* ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 ** ** Verify that 0 < r' < n and 0 < s' < n */ SECITEM_TO_MPINT(ecParams->order, &n); if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); goto cleanup; /* will return rv == SECFailure */ } /* ** ANSI X9.62, Section 5.4.2, Step 3 ** ** c = (s')**-1 mod n */ CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */ /* ** ANSI X9.62, Section 5.4.2, Step 4 ** ** u1 = ((HASH(M')) * c) mod n */ SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */ /* In the definition of EC signing, digests are truncated * to the length of n in bits. * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); if (digest->len*8 > obits) { /* u1 = HASH(M') */ mpl_rsh(&u1,&u1,digest->len*8 - obits); } #if EC_DEBUG mp_todecimal(&r_, mpstr); printf("r_: %s (dec)\n", mpstr); mp_todecimal(&s_, mpstr); printf("s_: %s (dec)\n", mpstr); mp_todecimal(&c, mpstr); printf("c : %s (dec)\n", mpstr); mp_todecimal(&u1, mpstr); printf("digest: %s (dec)\n", mpstr); #endif CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */ /* ** ANSI X9.62, Section 5.4.2, Step 4 ** ** u2 = ((r') * c) mod n */ CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) ); /* ** ANSI X9.62, Section 5.4.3, Step 1 ** ** Compute u1*G + u2*Q ** Here, A = u1.G B = u2.Q and C = A + B ** If the result, C, is the point at infinity, reject the signature */ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) != SECSuccess) { rv = SECFailure; goto cleanup; } if (ec_point_at_infinity(&pointC)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); rv = SECFailure; goto cleanup; } CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) ); /* ** ANSI X9.62, Section 5.4.4, Step 2 ** ** v = x1 mod n */ CHECK_MPI_OK( mp_mod(&x1, &n, &v) ); #if EC_DEBUG mp_todecimal(&r_, mpstr); printf("r_: %s (dec)\n", mpstr); mp_todecimal(&v, mpstr); printf("v : %s (dec)\n", mpstr); #endif /* ** ANSI X9.62, Section 5.4.4, Step 3 ** ** Verification: v == r' */ if (mp_cmp(&v, &r_)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); rv = SECFailure; /* Signature failed to verify. */ } else { rv = SECSuccess; /* Signature verified. */ } #if EC_DEBUG mp_todecimal(&u1, mpstr); printf("u1: %s (dec)\n", mpstr); mp_todecimal(&u2, mpstr); printf("u2: %s (dec)\n", mpstr); mp_tohex(&x1, mpstr); printf("x1: %s\n", mpstr); mp_todecimal(&v, mpstr); printf("v : %s (dec)\n", mpstr); #endif cleanup: mp_clear(&r_); mp_clear(&s_); mp_clear(&c); mp_clear(&u1); mp_clear(&u2); mp_clear(&x1); mp_clear(&v); mp_clear(&n); if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } #if EC_DEBUG printf("ECDSA verification %s\n", (rv == SECSuccess) ? "succeeded" : "failed"); #endif #else PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); #endif /* NSS_ENABLE_ECC */ return rv; }
/** Sign a hash with DSA @param in The hash to sign @param inlen The length of the hash to sign @param r The "r" integer of the signature (caller must initialize with mp_init() first) @param s The "s" integer of the signature (caller must initialize with mp_init() first) @param key A private DSA key @return CRYPT_OK if successful */ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, mp_int_t r, mp_int_t s, dsa_key * key) { mp_int k, kinv, tmp; unsigned char *buf; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(key != NULL); if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* check group order size */ if (key->qord >= LTC_MDSA_MAX_GROUP) { return CRYPT_INVALID_ARG; } buf = XMALLOC(LTC_MDSA_MAX_GROUP); if (buf == NULL) { return CRYPT_MEM; } /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } retry: do { /* gen random k */ get_random_bytes(buf, key->qord); /* read k */ if ((err = mp_read_unsigned_bin(&k, buf, key->qord)) != CRYPT_OK) { goto error; } /* k > 1 ? */ if (mp_cmp_d(&k, 1) != LTC_MP_GT) { goto retry; } /* test gcd */ if ((err = mp_gcd(&k, &key->q, &tmp)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(&tmp, 1) != LTC_MP_EQ); /* now find 1/k mod q */ if ((err = mp_invmod(&k, &key->q, &kinv)) != CRYPT_OK) { goto error; } /* now find r = g^k mod p mod q */ if ((err = mp_exptmod(&key->g, &k, &key->p, r)) != CRYPT_OK) { goto error; } if ((err = mp_mod(r, &key->q, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { goto retry; } /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(&key->x, r, s)) != CRYPT_OK) { goto error; } if ((err = mp_add(s, &tmp, s)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(s, &kinv, &key->q, s)) != CRYPT_OK) { goto error; } if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; error: mp_clear_multi(&k, &kinv, &tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, LTC_MDSA_MAX_GROUP); #endif XFREE(buf); return err; }
/* Strong Lucas-Selfridge test. returns MP_YES if it is a strong L-S prime, MP_NO if it is composite Code ported from Thomas Ray Nicely's implementation of the BPSW test at http://www.trnicely.net/misc/bpsw.html Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>. Released into the public domain by the author, who disclaims any legal liability arising from its use The multi-line comments are made by Thomas R. Nicely and are copied verbatim. Additional comments marked "CZ" (without the quotes) are by the code-portist. (If that name sounds familiar, he is the guy who found the fdiv bug in the Pentium (P5x, I think) Intel processor) */ int mp_prime_strong_lucas_selfridge(const mp_int *a, int *result) { /* CZ TODO: choose better variable names! */ mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz; /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */ int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits; int e; int isset; *result = MP_NO; /* Find the first element D in the sequence {5, -7, 9, -11, 13, ...} such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory indicates that, if N is not a perfect square, D will "nearly always" be "small." Just in case, an overflow trap for D is included. */ if ((e = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz, NULL)) != MP_OKAY) { return e; } D = 5; sign = 1; for (;;) { Ds = sign * D; sign = -sign; if ((e = mp_set_long(&Dz, (unsigned long)D)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) { goto LBL_LS_ERR; } /* if 1 < GCD < N then N is composite with factor "D", and Jacobi(D,N) is technically undefined (but often returned as zero). */ if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) { goto LBL_LS_ERR; } if (Ds < 0) { Dz.sign = MP_NEG; } if ((e = mp_kronecker(&Dz, a, &J)) != MP_OKAY) { goto LBL_LS_ERR; } if (J == -1) { break; } D += 2; if (D > (INT_MAX - 2)) { e = MP_VAL; goto LBL_LS_ERR; } } P = 1; /* Selfridge's choice */ Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */ /* NOTE: The conditions (a) N does not divide Q, and (b) D is square-free or not a perfect square, are included by some authors; e.g., "Prime numbers and computer methods for factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston), p. 130. For this particular application of Lucas sequences, these conditions were found to be immaterial. */ /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the odd positive integer d and positive integer s for which N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test). The strong Lucas-Selfridge test then returns N as a strong Lucas probable prime (slprp) if any of the following conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0, V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0 (all equalities mod N). Thus d is the highest index of U that must be computed (since V_2m is independent of U), compared to U_{N+1} for the standard Lucas-Selfridge test; and no index of V beyond (N+1)/2 is required, just as in the standard Lucas-Selfridge test. However, the quantity Q^d must be computed for use (if necessary) in the latter stages of the test. The result is that the strong Lucas-Selfridge test has a running time only slightly greater (order of 10 %) than that of the standard Lucas-Selfridge test, while producing only (roughly) 30 % as many pseudoprimes (and every strong Lucas pseudoprime is also a standard Lucas pseudoprime). Thus the evidence indicates that the strong Lucas-Selfridge test is more effective than the standard Lucas-Selfridge test, and a Baillie-PSW test based on the strong Lucas-Selfridge test should be more reliable. */ if ((e = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) { goto LBL_LS_ERR; } s = mp_cnt_lsb(&Np1); /* CZ * This should round towards zero because * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp() * and mp_div_2d() is equivalent. Additionally: * dividing an even number by two does not produce * any leftovers. */ if ((e = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) { goto LBL_LS_ERR; } /* We must now compute U_d and V_d. Since d is odd, the accumulated values U and V are initialized to U_1 and V_1 (if the target index were even, U and V would be initialized instead to U_0=0 and V_0=2). The values of U_2m and V_2m are also initialized to U_1 and V_1; the FOR loop calculates in succession U_2 and V_2, U_4 and V_4, U_8 and V_8, etc. If the corresponding bits (1, 2, 3, ...) of t are on (the zero bit having been accounted for in the initialization of U and V), these values are then combined with the previous totals for U and V, using the composition formulas for addition of indices. */ mp_set(&Uz, 1uL); /* U=U_1 */ mp_set(&Vz, (mp_digit)P); /* V=V_1 */ mp_set(&U2mz, 1uL); /* U_1 */ mp_set(&V2mz, (mp_digit)P); /* V_1 */ if (Q < 0) { Q = -Q; if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } Qmz.sign = MP_NEG; Q2mz.sign = MP_NEG; Qkdz.sign = MP_NEG; Q = -Q; } else { if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } } Nbits = mp_count_bits(&Dz); for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */ /* Formulas for doubling of indices (carried out mod N). Note that * the indices denoted as "2m" are actually powers of 2, specifically * 2^(ul-1) beginning each loop and 2^ul ending each loop. * * U_2m = U_m*V_m * V_2m = V_m*V_m - 2*Q^m */ if ((e = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Must calculate powers of Q for use in V_2m, also for Q^d later */ if ((e = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */ if ((e = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((isset = mp_get_bit(&Dz, u)) == MP_VAL) { e = isset; goto LBL_LS_ERR; } if (isset == MP_YES) { /* Formulas for addition of indices (carried out mod N); * * U_(m+n) = (U_m*V_n + U_n*V_m)/2 * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2 * * Be careful with division by 2 (mod N)! */ if ((e = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = s_mp_mul_si(&T4z, (long)Ds, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Uz) != MP_NO) { if ((e = mp_add(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } /* CZ * This should round towards negative infinity because * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp(). * But mp_div_2() does not do so, it is truncating instead. */ if ((e = mp_div_2(&Uz, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Uz.sign == MP_NEG) && (mp_isodd(&Uz) != MP_NO)) { if ((e = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Vz) != MP_NO) { if ((e = mp_add(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_div_2(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Vz.sign == MP_NEG) && (mp_isodd(&Vz) != MP_NO)) { if ((e = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_mod(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Calculating Q^d for later use */ if ((e = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ if ((mp_iszero(&Uz) != MP_NO) || (mp_iszero(&Vz) != MP_NO)) { *result = MP_YES; goto LBL_LS_ERR; } /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed., 1995/6) omits the condition V0 on p.142, but includes it on p. 130. The condition is NECESSARY; otherwise the test will return false negatives---e.g., the primes 29 and 2000029 will be returned as composite. */ /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d} by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of these are congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ /* Initialize 2*Q^(d*2^r) for V_2m */ if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } for (r = 1; r < s; r++) { if ((e = mp_sqr(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_iszero(&Vz) != MP_NO) { *result = MP_YES; goto LBL_LS_ERR; } /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */ if (r < (s - 1)) { if ((e = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } LBL_LS_ERR: mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL); return e; }
/** Verify an ECC signature @param sig The signature to verify @param siglen The length of the signature (octets) @param hash The hash (message digest) that was signed @param hashlen The length of the hash (octets) @param stat Result of signature, 1==valid, 0==invalid @param key The corresponding public ECC key @return CRYPT_OK if successful (even if the signature is not valid) */ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, ecc_key *key) { ecc_point *mG, *mQ; void *r, *s, *v, *w, *u1, *u2, *e, *p, *m; void *mp; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; mp = NULL; /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } /* allocate ints */ if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != CRYPT_OK) { return CRYPT_MEM; } /* allocate points */ mG = ltc_ecc_new_point(); mQ = ltc_ecc_new_point(); if (mQ == NULL || mG == NULL) { err = CRYPT_MEM; goto error; } /* parse header */ if ((err = der_decode_sequence_multi(sig, siglen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } /* get the order */ if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } /* get the modulus */ if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } /* check for zero */ if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } /* read hash */ if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, (int)hashlen)) != CRYPT_OK) { goto error; } /* w = s^-1 mod n */ if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } /* u1 = ew */ if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } /* u2 = rw */ if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } /* find mG and mQ */ if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } /* compute u1*mG + u2*mQ = mG */ if (ltc_mp.ecc_mul2add == NULL) { if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto error; } if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto error; } /* find the montgomery mp */ if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } /* add them */ if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto error; } /* reduce */ if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } } else { /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK) { goto error; } } /* v = X_x1 mod n */ if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } /* does v == r */ if (mp_cmp(v, r) == LTC_MP_EQ) { *stat = 1; } /* clear up and return */ err = CRYPT_OK; error: ltc_ecc_del_point(mG); ltc_ecc_del_point(mQ); mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); if (mp != NULL) { mp_montgomery_free(mp); } return err; }
static SECStatus rsa_build_from_primes(mp_int *p, mp_int *q, mp_int *e, PRBool needPublicExponent, mp_int *d, PRBool needPrivateExponent, RSAPrivateKey *key, unsigned int keySizeInBits) { mp_int n, phi; mp_int psub1, qsub1, tmp; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&phi) = 0; MP_DIGITS(&psub1) = 0; MP_DIGITS(&qsub1) = 0; MP_DIGITS(&tmp) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&phi) ); CHECK_MPI_OK( mp_init(&psub1) ); CHECK_MPI_OK( mp_init(&qsub1) ); CHECK_MPI_OK( mp_init(&tmp) ); /* 1. Compute n = p*q */ CHECK_MPI_OK( mp_mul(p, q, &n) ); /* verify that the modulus has the desired number of bits */ if ((unsigned)mpl_significant_bits(&n) != keySizeInBits) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* at least one exponent must be given */ PORT_Assert(!(needPublicExponent && needPrivateExponent)); /* 2. Compute phi = (p-1)*(q-1) */ CHECK_MPI_OK( mp_sub_d(p, 1, &psub1) ); CHECK_MPI_OK( mp_sub_d(q, 1, &qsub1) ); if (needPublicExponent || needPrivateExponent) { CHECK_MPI_OK( mp_mul(&psub1, &qsub1, &phi) ); /* 3. Compute d = e**-1 mod(phi) */ /* or e = d**-1 mod(phi) as necessary */ if (needPublicExponent) { err = mp_invmod(d, &phi, e); } else { err = mp_invmod(e, &phi, d); } } else { err = MP_OKAY; } /* Verify that phi(n) and e have no common divisors */ if (err != MP_OKAY) { if (err == MP_UNDEF) { PORT_SetError(SEC_ERROR_NEED_RANDOM); err = MP_OKAY; /* to keep PORT_SetError from being called again */ rv = SECFailure; } goto cleanup; } /* 4. Compute exponent1 = d mod (p-1) */ CHECK_MPI_OK( mp_mod(d, &psub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent1, key->arena); /* 5. Compute exponent2 = d mod (q-1) */ CHECK_MPI_OK( mp_mod(d, &qsub1, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->exponent2, key->arena); /* 6. Compute coefficient = q**-1 mod p */ CHECK_MPI_OK( mp_invmod(q, p, &tmp) ); MPINT_TO_SECITEM(&tmp, &key->coefficient, key->arena); /* copy our calculated results, overwrite what is there */ key->modulus.data = NULL; MPINT_TO_SECITEM(&n, &key->modulus, key->arena); key->privateExponent.data = NULL; MPINT_TO_SECITEM(d, &key->privateExponent, key->arena); key->publicExponent.data = NULL; MPINT_TO_SECITEM(e, &key->publicExponent, key->arena); key->prime1.data = NULL; MPINT_TO_SECITEM(p, &key->prime1, key->arena); key->prime2.data = NULL; MPINT_TO_SECITEM(q, &key->prime2, key->arena); cleanup: mp_clear(&n); mp_clear(&phi); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&tmp); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
static SECStatus dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, const unsigned char *kb) { mp_int p, q, g; /* PQG parameters */ mp_int x, k; /* private key & pseudo-random integer */ mp_int r, s; /* tuple (r, s) is signature) */ mp_err err = MP_OKAY; SECStatus rv = SECSuccess; unsigned int dsa_subprime_len, dsa_signature_len, offset; SECItem localDigest; unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; /* FIPS-compliance dictates that digest is a SHA hash. */ /* Check args. */ if (!key || !signature || !digest) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } dsa_subprime_len = PQG_GetLength(&key->params.subPrime); dsa_signature_len = dsa_subprime_len*2; if ((signature->len < dsa_signature_len) || (digest->len > HASH_LENGTH_MAX) || (digest->len < SHA1_LENGTH)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* DSA accepts digests not equal to dsa_subprime_len, if the * digests are greater, then they are truncated to the size of * dsa_subprime_len, using the left most bits. If they are less * then they are padded on the left.*/ PORT_Memset(localDigestData, 0, dsa_subprime_len); offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; PORT_Memcpy(localDigestData+offset, digest->data, dsa_subprime_len - offset); localDigest.data = localDigestData; localDigest.len = dsa_subprime_len; /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&g) = 0; MP_DIGITS(&x) = 0; MP_DIGITS(&k) = 0; MP_DIGITS(&r) = 0; MP_DIGITS(&s) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&x) ); CHECK_MPI_OK( mp_init(&k) ); CHECK_MPI_OK( mp_init(&r) ); CHECK_MPI_OK( mp_init(&s) ); /* ** Convert stored PQG and private key into MPI integers. */ SECITEM_TO_MPINT(key->params.prime, &p); SECITEM_TO_MPINT(key->params.subPrime, &q); SECITEM_TO_MPINT(key->params.base, &g); SECITEM_TO_MPINT(key->privateValue, &x); OCTETS_TO_MPINT(kb, &k, dsa_subprime_len); /* ** FIPS 186-1, Section 5, Step 1 ** ** r = (g**k mod p) mod q */ CHECK_MPI_OK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */ CHECK_MPI_OK( mp_mod(&r, &q, &r) ); /* r = r mod q */ /* ** FIPS 186-1, Section 5, Step 2 ** ** s = (k**-1 * (HASH(M) + x*r)) mod q */ SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ CHECK_MPI_OK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */ CHECK_MPI_OK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */ CHECK_MPI_OK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */ CHECK_MPI_OK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */ /* ** verify r != 0 and s != 0 ** mentioned as optional in FIPS 186-1. */ if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) { PORT_SetError(SEC_ERROR_NEED_RANDOM); rv = SECFailure; goto cleanup; } /* ** Step 4 ** ** Signature is tuple (r, s) */ err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len); if (err < 0) goto cleanup; err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len, dsa_subprime_len); if (err < 0) goto cleanup; err = MP_OKAY; signature->len = dsa_signature_len; cleanup: PORT_Memset(localDigestData, 0, DSA_MAX_SUBPRIME_LEN); mp_clear(&p); mp_clear(&q); mp_clear(&g); mp_clear(&x); mp_clear(&k); mp_clear(&r); mp_clear(&s); if (err) { translate_mpi_error(err); rv = SECFailure; } return rv; }
/* Reduces an integer to a field element. */ mp_err ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth) { return mp_mod(a, &meth->irr, r); }
/* signature is caller-supplied buffer of at least 20 bytes. ** On input, signature->len == size of buffer to hold signature. ** digest->len == size of digest. */ SECStatus DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, const SECItem *digest) { /* FIPS-compliance dictates that digest is a SHA hash. */ mp_int p, q, g; /* PQG parameters */ mp_int r_, s_; /* tuple (r', s') is received signature) */ mp_int u1, u2, v, w; /* intermediate values used in verification */ mp_int y; /* public key */ mp_err err; int dsa_subprime_len, dsa_signature_len, offset; SECItem localDigest; unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; SECStatus verified = SECFailure; /* Check args. */ if (!key || !signature || !digest ) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } dsa_subprime_len = PQG_GetLength(&key->params.subPrime); dsa_signature_len = dsa_subprime_len*2; if ((signature->len != dsa_signature_len) || (digest->len > HASH_LENGTH_MAX) || (digest->len < SHA1_LENGTH)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* DSA accepts digests not equal to dsa_subprime_len, if the * digests are greater, than they are truncated to the size of * dsa_subprime_len, using the left most bits. If they are less * then they are padded on the left.*/ PORT_Memset(localDigestData, 0, dsa_subprime_len); offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; PORT_Memcpy(localDigestData+offset, digest->data, dsa_subprime_len - offset); localDigest.data = localDigestData; localDigest.len = dsa_subprime_len; /* Initialize MPI integers. */ MP_DIGITS(&p) = 0; MP_DIGITS(&q) = 0; MP_DIGITS(&g) = 0; MP_DIGITS(&y) = 0; MP_DIGITS(&r_) = 0; MP_DIGITS(&s_) = 0; MP_DIGITS(&u1) = 0; MP_DIGITS(&u2) = 0; MP_DIGITS(&v) = 0; MP_DIGITS(&w) = 0; CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&g) ); CHECK_MPI_OK( mp_init(&y) ); CHECK_MPI_OK( mp_init(&r_) ); CHECK_MPI_OK( mp_init(&s_) ); CHECK_MPI_OK( mp_init(&u1) ); CHECK_MPI_OK( mp_init(&u2) ); CHECK_MPI_OK( mp_init(&v) ); CHECK_MPI_OK( mp_init(&w) ); /* ** Convert stored PQG and public key into MPI integers. */ SECITEM_TO_MPINT(key->params.prime, &p); SECITEM_TO_MPINT(key->params.subPrime, &q); SECITEM_TO_MPINT(key->params.base, &g); SECITEM_TO_MPINT(key->publicValue, &y); /* ** Convert received signature (r', s') into MPI integers. */ OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len); OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len); /* ** Verify that 0 < r' < q and 0 < s' < q */ if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) { /* err is zero here. */ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); goto cleanup; /* will return verified == SECFailure */ } /* ** FIPS 186-1, Section 6, Step 1 ** ** w = (s')**-1 mod q */ CHECK_MPI_OK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */ /* ** FIPS 186-1, Section 6, Step 2 ** ** u1 = ((Hash(M')) * w) mod q */ SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */ CHECK_MPI_OK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */ /* ** FIPS 186-1, Section 6, Step 3 ** ** u2 = ((r') * w) mod q */ CHECK_MPI_OK( mp_mulmod(&r_, &w, &q, &u2) ); /* ** FIPS 186-1, Section 6, Step 4 ** ** v = ((g**u1 * y**u2) mod p) mod q */ CHECK_MPI_OK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */ CHECK_MPI_OK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */ CHECK_MPI_OK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */ CHECK_MPI_OK( mp_mod(&v, &q, &v) ); /* v = v mod q */ /* ** Verification: v == r' */ if (mp_cmp(&v, &r_)) { PORT_SetError(SEC_ERROR_BAD_SIGNATURE); verified = SECFailure; /* Signature failed to verify. */ } else { verified = SECSuccess; /* Signature verified. */ } cleanup: mp_clear(&p); mp_clear(&q); mp_clear(&g); mp_clear(&y); mp_clear(&r_); mp_clear(&s_); mp_clear(&u1); mp_clear(&u2); mp_clear(&v); mp_clear(&w); if (err) { translate_mpi_error(err); } return verified; }
/* computes the modular inverse via binary extended euclidean algorithm, * that is c = 1/a mod b * * Based on slow invmod except this is optimized for the case where b is * odd as per HAC Note 14.64 on pp. 610 */ int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) { mp_int x, y, u, v, B, D; int res, neg; /* 2. [modified] b must be odd */ if (mp_iseven (b) == 1) { return MP_VAL; } /* init all our temps */ if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { return res; } /* x == modulus, y == value to invert */ if ((res = mp_copy (b, &x)) != MP_OKAY) { goto LBL_ERR; } /* we need y = |a| */ if ((res = mp_mod (a, b, &y)) != MP_OKAY) { goto LBL_ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { goto LBL_ERR; } mp_set (&D, 1); top: /* 4. while u is even do */ while (mp_iseven (&u) == 1) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto LBL_ERR; } /* 4.2 if B is odd then */ if (mp_isodd (&B) == 1) { if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto LBL_ERR; } } /* B = B/2 */ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { goto LBL_ERR; } } /* 5. while v is even do */ while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto LBL_ERR; } /* 5.2 if D is odd then */ if (mp_isodd (&D) == 1) { /* D = (D-x)/2 */ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto LBL_ERR; } } /* D = D/2 */ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { goto LBL_ERR; } } /* 6. if u >= v then */ if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { goto LBL_ERR; } } else { /* v - v - u, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { goto LBL_ERR; } } /* if not zero goto step 4 */ if (mp_iszero (&u) == 0) { goto top; } /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; goto LBL_ERR; } /* b is now the inverse */ neg = a->sign; while (D.sign == MP_NEG) { if ((res = mp_add (&D, b, &D)) != MP_OKAY) { goto LBL_ERR; } } mp_exch (&D, c); c->sign = neg; res = MP_OKAY; LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); return res; }
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp) { int err; ecc_point *base; void *prime, *order; unsigned char *buf; int keysize; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); LTC_ARGCHK(dp != NULL); /* good prng? */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } key->idx = -1; key->dp = dp; keysize = dp->size; /* allocate ram */ base = NULL; buf = XMALLOC(ECC_MAXSIZE); if (buf == NULL) { return CRYPT_MEM; } /* make up random string */ if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; goto ERR_BUF; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, &order, NULL)) != CRYPT_OK) { goto ERR_BUF; } base = ltc_ecc_new_point(); if (base == NULL) { err = CRYPT_MEM; goto errkey; } /* read in the specs for this key */ if ((err = mp_read_radix(prime, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(order, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_set(base->z, 1)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto errkey; } /* the key should be smaller than the order of base point */ if (mp_cmp(key->k, order) != LTC_MP_LT) { if((err = mp_mod(key->k, order, key->k)) != CRYPT_OK) { goto errkey; } } /* make the public key */ if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto errkey; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; goto cleanup; errkey: mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); cleanup: ltc_ecc_del_point(base); mp_clear_multi(prime, order, NULL); ERR_BUF: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif XFREE(buf); return err; }
SECStatus RSA_PrivateKeyCheck(RSAPrivateKey *key) { mp_int p, q, n, psub1, qsub1, e, d, d_p, d_q, qInv, res; mp_err err = MP_OKAY; SECStatus rv = SECSuccess; MP_DIGITS(&n) = 0; MP_DIGITS(&psub1)= 0; MP_DIGITS(&qsub1)= 0; MP_DIGITS(&e) = 0; MP_DIGITS(&d) = 0; MP_DIGITS(&d_p) = 0; MP_DIGITS(&d_q) = 0; MP_DIGITS(&qInv) = 0; MP_DIGITS(&res) = 0; CHECK_MPI_OK( mp_init(&n) ); CHECK_MPI_OK( mp_init(&p) ); CHECK_MPI_OK( mp_init(&q) ); CHECK_MPI_OK( mp_init(&psub1)); CHECK_MPI_OK( mp_init(&qsub1)); CHECK_MPI_OK( mp_init(&e) ); CHECK_MPI_OK( mp_init(&d) ); CHECK_MPI_OK( mp_init(&d_p) ); CHECK_MPI_OK( mp_init(&d_q) ); CHECK_MPI_OK( mp_init(&qInv) ); CHECK_MPI_OK( mp_init(&res) ); SECITEM_TO_MPINT(key->modulus, &n); SECITEM_TO_MPINT(key->prime1, &p); SECITEM_TO_MPINT(key->prime2, &q); SECITEM_TO_MPINT(key->publicExponent, &e); SECITEM_TO_MPINT(key->privateExponent, &d); SECITEM_TO_MPINT(key->exponent1, &d_p); SECITEM_TO_MPINT(key->exponent2, &d_q); SECITEM_TO_MPINT(key->coefficient, &qInv); /* p > q */ if (mp_cmp(&p, &q) <= 0) { /* mind the p's and q's (and d_p's and d_q's) */ SECItem tmp; mp_exch(&p, &q); mp_exch(&d_p,&d_q); tmp = key->prime1; key->prime1 = key->prime2; key->prime2 = tmp; tmp = key->exponent1; key->exponent1 = key->exponent2; key->exponent2 = tmp; } #define VERIFY_MPI_EQUAL(m1, m2) \ if (mp_cmp(m1, m2) != 0) { \ rv = SECFailure; \ goto cleanup; \ } #define VERIFY_MPI_EQUAL_1(m) \ if (mp_cmp_d(m, 1) != 0) { \ rv = SECFailure; \ goto cleanup; \ } /* * The following errors cannot be recovered from. */ /* n == p * q */ CHECK_MPI_OK( mp_mul(&p, &q, &res) ); VERIFY_MPI_EQUAL(&res, &n); /* gcd(e, p-1) == 1 */ CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); CHECK_MPI_OK( mp_gcd(&e, &psub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* gcd(e, q-1) == 1 */ CHECK_MPI_OK( mp_sub_d(&q, 1, &qsub1) ); CHECK_MPI_OK( mp_gcd(&e, &qsub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* d*e == 1 mod p-1 */ CHECK_MPI_OK( mp_mulmod(&d, &e, &psub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* d*e == 1 mod q-1 */ CHECK_MPI_OK( mp_mulmod(&d, &e, &qsub1, &res) ); VERIFY_MPI_EQUAL_1(&res); /* * The following errors can be recovered from. */ /* d_p == d mod p-1 */ CHECK_MPI_OK( mp_mod(&d, &psub1, &res) ); if (mp_cmp(&d_p, &res) != 0) { /* swap in the correct value */ CHECK_SEC_OK( swap_in_key_value(key->arena, &res, &key->exponent1) ); } /* d_q == d mod q-1 */ CHECK_MPI_OK( mp_mod(&d, &qsub1, &res) ); if (mp_cmp(&d_q, &res) != 0) { /* swap in the correct value */ CHECK_SEC_OK( swap_in_key_value(key->arena, &res, &key->exponent2) ); } /* q * q**-1 == 1 mod p */ CHECK_MPI_OK( mp_mulmod(&q, &qInv, &p, &res) ); if (mp_cmp_d(&res, 1) != 0) { /* compute the correct value */ CHECK_MPI_OK( mp_invmod(&q, &p, &qInv) ); CHECK_SEC_OK( swap_in_key_value(key->arena, &qInv, &key->coefficient) ); } cleanup: mp_clear(&n); mp_clear(&p); mp_clear(&q); mp_clear(&psub1); mp_clear(&qsub1); mp_clear(&e); mp_clear(&d); mp_clear(&d_p); mp_clear(&d_q); mp_clear(&qInv); mp_clear(&res); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; } return rv; }
/** Create a Katja key @param prng An active PRNG state @param wprng The index of the PRNG desired @param size The size of the modulus (key size) desired (octets) @param key [out] Destination of a newly created private key pair @return CRYPT_OK if successful, upon error all allocated ram is freed */ int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key) { void *p, *q, *tmp1, *tmp2; int err; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); if ((size < (MIN_KAT_SIZE/8)) || (size > (MAX_KAT_SIZE/8))) { return CRYPT_INVALID_KEYSIZE; } if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, NULL)) != CRYPT_OK) { return err; } /* divide size by three */ size = (((size << 3) / 3) + 7) >> 3; /* make prime "q" (we negate size to make q == 3 mod 4) */ if ((err = rand_prime(q, -size, prng, wprng)) != CRYPT_OK) { goto done; } if ((err = mp_sub_d(q, 1, tmp1)) != CRYPT_OK) { goto done; } /* make prime "p" */ do { if ((err = rand_prime(p, size+1, prng, wprng)) != CRYPT_OK) { goto done; } if ((err = mp_gcd(p, tmp1, tmp2)) != CRYPT_OK) { goto done; } } while (mp_cmp_d(tmp2, 1) != LTC_MP_EQ); /* make key */ if ((err = mp_init_multi(&key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, &key->pq, NULL)) != CRYPT_OK) { goto error; } /* n=p^2q and 1/n mod pq */ if ((err = mp_copy( p, key->p)) != CRYPT_OK) { goto error2; } if ((err = mp_copy( q, key->q)) != CRYPT_OK) { goto error2; } if ((err = mp_mul(key->p, key->q, key->pq)) != CRYPT_OK) { goto error2; } /* tmp1 = pq */ if ((err = mp_mul(key->pq, key->p, key->N)) != CRYPT_OK) { goto error2; } /* N = p^2q */ if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto error2; } /* tmp1 = q-1 */ if ((err = mp_sub_d( q, 1, tmp2)) != CRYPT_OK) { goto error2; } /* tmp2 = p-1 */ if ((err = mp_lcm(tmp1, tmp2, key->d)) != CRYPT_OK) { goto error2; } /* tmp1 = lcd(p-1,q-1) */ if ((err = mp_invmod( key->N, key->d, key->d)) != CRYPT_OK) { goto error2; } /* key->d = 1/N mod pq */ /* optimize for CRT now */ /* find d mod q-1 and d mod p-1 */ if ((err = mp_mod( key->d, tmp1, key->dP)) != CRYPT_OK) { goto error2; } /* dP = d mod p-1 */ if ((err = mp_mod( key->d, tmp2, key->dQ)) != CRYPT_OK) { goto error2; } /* dQ = d mod q-1 */ if ((err = mp_invmod( q, p, key->qP)) != CRYPT_OK) { goto error2; } /* qP = 1/q mod p */ /* set key type (in this case it's CRT optimized) */ key->type = PK_PRIVATE; /* return ok and free temps */ err = CRYPT_OK; goto done; error2: mp_clear_multi( key->d, key->N, key->dQ, key->dP, key->qP, key->p, key->q, key->pq, NULL); error: done: mp_clear_multi( tmp2, tmp1, p, q, NULL); return err; }