static feeReturn feeGenPrivate(pubKeyInst *pkinst, const unsigned char *passwd, unsigned passwdLen, char hashPasswd) { unsigned privLen; // desired size of pkinst->privData feeHash *hash = NULL; // a malloc'd array unsigned digestLen; // size of MD5 digest unsigned dataSize; // min(privLen, passwdLen) unsigned numDigests = 0; unsigned i; unsigned char *cp; unsigned toMove; // for this digest unsigned moved; // total digested unsigned char *digest = NULL; unsigned char *privData = NULL; // temp, before modg(curveOrder) giant corder; // lesser of two curve orders /* * generate privData which is just larger than the smaller * curve order. * We'll take the result mod the curve order when we're done. * Note we do *not* have to free corder - it's a pointer to a giant * in pkinst->cp. */ corder = lesserX1Order(pkinst->cp); CKASSERT(!isZero(corder)); privLen = (bitlen(corder) / 8) + 1; if(!hashPasswd) { /* * Caller trusts the incoming entropy. Verify it's big enough and proceed. */ if(passwdLen < privLen) { return FR_ShortPrivData; } privLen = passwdLen; privData = (unsigned char *)passwd; goto finishUp; } if(passwdLen < 2) { return FR_IllegalArg; } /* * Calculate how many MD5 digests we'll generate. */ if(privLen > passwdLen) { dataSize = passwdLen; } else { dataSize = privLen; } digestLen = feeHashDigestLen(); numDigests = (dataSize + digestLen - 1) / digestLen; hash = (void**) fmalloc(numDigests * sizeof(feeHash)); for(i=0; i<numDigests; i++) { hash[i] = feeHashAlloc(); } /* * fill digests with passwd data, digestLen (or resid length) * at a time. If (passwdLen > privLen), last digest will hash all * remaining passwd data. */ cp = (unsigned char *)passwd; moved = 0; for(i=0; i<numDigests; i++) { if(i == (numDigests - 1)) { // last digest toMove = passwdLen - moved; } else { toMove = digestLen; } feeHashAddData(hash[i], cp, toMove); cp += toMove; moved += toMove; } /* * copy digests to privData, up to privLen bytes. Pad with * additional copies of digests if necessary. */ privData = (unsigned char*) fmalloc(privLen); cp = privData; moved = 0; i = 0; // digest number for(moved=0; moved<privLen; ) { if((moved + digestLen) > privLen) { toMove = privLen - moved; } else { toMove = digestLen; } digest = feeHashDigest(hash[i++]); bcopy(digest, cp, toMove); cp += toMove; moved += toMove; if(i == numDigests) { i = 0; // wrap to 0, start padding } } finishUp: /* * Convert to giant, justify result to within [2, lesserX1Order] */ pkinst->privGiant = giant_with_data(privData, privLen); #if FEE_DEBUG if(isZero(pkinst->privGiant)) { printf("feeGenPrivate: privData = 0!\n"); } #endif // FEE_DEBUG lesserX1OrderJustify(pkinst->privGiant, pkinst->cp); if(hashPasswd) { memset(privData, 0, privLen); ffree(privData); for(i=0; i<numDigests; i++) { feeHashFree(hash[i]); } ffree(hash); } return FR_Success; }
key new_public_with_key(key old_key, curveParams *cp) { key result; result = new_public(cp, old_key->twist); CKASSERT((old_key->x != NULL) && (old_key->y != NULL)); CKASSERT((result->x != NULL) && (result->y != NULL)); gtog(old_key->x, result->x); gtog(old_key->y, result->y); return result; }
/* * Specify private data for key created by new_public(). * Generates k->x. */ void set_priv_key_giant(key k, giant privGiant) { curveParams *cp = k->cp; /* elliptiy multiply of initial public point times private key */ #if CRYPTKIT_ELL_PROJ_ENABLE if((k->twist == CURVE_PLUS) && (cp->curveType == FCT_Weierstrass)) { /* projective */ pointProj pt1 = newPointProj(cp->maxDigits); CKASSERT((cp->y1Plus != NULL) && (!isZero(cp->y1Plus))); CKASSERT(k->y != NULL); /* pt1 := {x1Plus, y1Plus, 1} */ gtog(cp->x1Plus, pt1->x); gtog(cp->y1Plus, pt1->y); int_to_giant(1, pt1->z); /* pt1 := pt1 * privateKey */ ellMulProjSimple(pt1, privGiant, cp); /* result back to {k->x, k->y} */ gtog(pt1->x, k->x); gtog(pt1->y, k->y); freePointProj(pt1); // FIXME - clear the giants } else { #else { #endif /* CRYPTKIT_ELL_PROJ_ENABLE */ /* FEE */ if(k->twist == CURVE_PLUS) { gtog(cp->x1Plus, k->x); } else { gtog(cp->x1Minus, k->x); } elliptic_simple(k->x, privGiant, k->cp); } } int key_equal(key one, key two) { if (keys_inconsistent(one, two)) return 0; return !gcompg(one->x, two->x); } static void make_base(curveParams *par, giant result) /* Jams result with 2^q-k. */ { gtog(par->basePrime, result); }
/* * g := g mod x1OrderPlus. Result may be zero. */ void x1OrderPlusMod(giant g, curveParams *cp) { CKASSERT(!isZero(cp->x1OrderPlus)); /* * Calculate reciprocal if we don't have it */ calcX1OrderPlusRecip(cp); modg_via_recip(cp->x1OrderPlus, cp->x1OrderPlusRecip, g); }
void x1OrderPlusJustify(giant g, curveParams *cp) { CKASSERT(!isZero(cp->x1OrderPlus)); /* * Calculate reciprocal if we don't have it */ calcX1OrderPlusRecip(cp); curveOrderJustifyWithRecip(g, cp->x1OrderPlus, cp->x1OrderPlusRecip); }
/* destgiant becomes equal to srcgiant */ void gtog(giant srcgiant, giant destgiant) { int numbytes; CKASSERT(srcgiant != NULL); numbytes = abs(srcgiant->sign) * GIANT_BYTES_PER_DIGIT; if (destgiant->capacity < abs(srcgiant->sign)) CKRaise("gtog overflow!!"); memcpy((char *)destgiant->n, (char *)srcgiant->n, numbytes); destgiant->sign = srcgiant->sign; }
/* * Simple projective multiply. * * pt := pt * k, result normalized. */ void ellMulProjSimple(pointProj pt0, giant k, curveParams *cp) { pointProjStruct pt1; // local, giants borrowed CKASSERT(isone(pt0->z)); CKASSERT(cp->curveType == FCT_Weierstrass); /* ellMulProj assumes constant pt0, can't pass as src and dst */ pt1.x = borrowGiant(cp->maxDigits); pt1.y = borrowGiant(cp->maxDigits); pt1.z = borrowGiant(cp->maxDigits); ellMulProj(pt0, &pt1, k, cp); normalizeProj(&pt1, cp); CKASSERT(isone(pt1.z)); ptopProj(&pt1, pt0); returnGiant(pt1.x); returnGiant(pt1.y); returnGiant(pt1.z); }
/* * This version is not normally used; it's for when the reciprocal of * curveOrder is not known and won't be used again. */ void curveOrderJustify(giant g, giant curveOrder) { giant recip; CKASSERT(!isZero(curveOrder)); recip = borrowGiant(2 * abs(g->sign)); make_recip(curveOrder, recip); curveOrderJustifyWithRecip(g, curveOrder, recip); returnGiant(recip); }
void make_base_prim(curveParams *cp) /* Jams cp->basePrime with 2^q-k. Assumes valid maxDigits, q, k. */ { giant tmp = borrowGiant(cp->maxDigits); CKASSERT(cp->primeType != FPT_General); int_to_giant(1, cp->basePrime); gshiftleft((int)cp->q, cp->basePrime); int_to_giant(cp->k, tmp); subg(tmp, cp->basePrime); returnGiant(tmp); }
void ellMulProj(pointProj pt0, pointProj pt1, giant k, curveParams *cp) /* General elliptic multiplication; pt1 := k*pt0 on the curve, with k an arbitrary integer. */ { giant x = pt0->x, y = pt0->y, z = pt0->z, xx = pt1->x, yy = pt1->y, zz = pt1->z; int ksign, hlen, klen, b, hb, kb; giant t0; CKASSERT(cp->curveType == FCT_Weierstrass); if(isZero(k)) { int_to_giant(1, xx); int_to_giant(1, yy); int_to_giant(0, zz); return; } t0 = borrowGiant(cp->maxDigits); ksign = k->sign; if(ksign < 0) negg(k); gtog(x,xx); gtog(y,yy); gtog(z,zz); gtog(k, t0); addg(t0, t0); addg(k, t0); /* t0 := 3k. */ hlen = bitlen(t0); klen = bitlen(k); for(b = hlen-2; b > 0; b--) { ellDoubleProj(pt1,cp); hb = bitval(t0, b); if(b < klen) kb = bitval(k, b); else kb = 0; if((hb != 0) && (kb == 0)) ellAddProj(pt1, pt0, cp); else if((hb == 0) && (kb !=0)) ellSubProj(pt1, pt0, cp); } if(ksign < 0) { ellNegProj(pt1, cp); k->sign = -k->sign; } returnGiant(t0); }
void normalizeProj(pointProj pt, curveParams *cp) /* Obtain actual x,y coords via normalization: {x,y,z} := {x/z^2, y/z^3, 1}. */ { giant x = pt->x, y = pt->y, z = pt->z; giant t1; CKASSERT(cp->curveType == FCT_Weierstrass); if(isZero(z)) { int_to_giant(1,x); int_to_giant(1,y); return; } t1 = borrowGiant(cp->maxDigits); binvg_cp(cp, z); // was binvaux(p, z); gtog(z, t1); gsquare(z); feemod(cp, z); mulg(z, x); feemod(cp, x); mulg(t1, z); mulg(z, y); feemod(cp, y); int_to_giant(1, z); returnGiant(t1); }
/* * New optimzation of curveOrderJustify using known reciprocal, 11 June 1997. * g is set to be within [2, curveOrder-2]. */ static void curveOrderJustifyWithRecip(giant g, giant curveOrder, giant recip) { giant tmp; CKASSERT(!isZero(curveOrder)); modg_via_recip(curveOrder, recip, g); // g now in [0, curveOrder-1] if(isZero(g)) { /* * First degenerate case - (g == 0) : set g := 2 */ dbgLog(("curveOrderJustify: case 1\n")); int_to_giant(2, g); return; } if(isone(g)) { /* * Second case - (g == 1) : set g := 2 */ dbgLog(("curveOrderJustify: case 2\n")); int_to_giant(2, g); return; } tmp = borrowGiant(g->capacity); gtog(g, tmp); iaddg(1, tmp); if(gcompg(tmp, curveOrder) == 0) { /* * Third degenerate case - (g == (curveOrder-1)) : set g -= 1 */ dbgLog(("curveOrderJustify: case 3\n")); int_to_giant(1, tmp); subg(tmp, g); } returnGiant(tmp); return; }
void findPointProj(pointProj pt, giant seed, curveParams *cp) /* Starting with seed, finds a random (projective) point {x,y,1} on curve. */ { giant x = pt->x, y = pt->y, z = pt->z; CKASSERT(cp->curveType == FCT_Weierstrass); feemod(cp, seed); while(1) { gtog(seed, x); gsquare(x); feemod(cp, x); // x := seed^2 addg(cp->a, x); // x := seed^2 + a mulg(seed,x); // x := seed^3 + a*seed addg(cp->b, x); feemod(cp, x); // x := seed^3 + a seed + b. /* test cubic form for having root. */ if(sqrtmod(x, cp)) break; iaddg(1, seed); } gtog(x, y); gtog(seed,x); int_to_giant(1, z); }
feeReturn feeECDSAVerify(const unsigned char *sigData, size_t sigDataLen, const unsigned char *data, unsigned dataLen, feePubKey pubKey, feeSigFormat format) { /* giant integers per IEEE P1363 notation */ giant h; // s^(-1) giant h1; // f h giant h2; // c times h giant littleC; // newGiant from ECDSA_decode giant littleD; // ditto giant c; // borrowed, full size giant d; // ditto giant cPrime = NULL; // i mod r pointProj h1G = NULL; // h1 'o' G pointProj h2W = NULL; // h2 'o' W key W; // i.e., their public key unsigned version; feeReturn frtn; curveParams *cp = feePubKeyCurveParams(pubKey); unsigned groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); int result; if(cp == NULL) { return FR_BadPubKey; } /* * First decode the byteRep string. */ frtn = ECDSA_decode( format, groupBytesLen, sigData, sigDataLen, &littleC, &littleD, &version); if(frtn) { return frtn; } /* * littleC and littleD have capacity = abs(sign), probably * not big enough.... */ c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); gtog(littleC, c); gtog(littleD, d); freeGiant(littleC); freeGiant(littleD); sigDbg(("ECDSA verify:\n")); /* * Verify that c and d are within [1,group_order-1] */ if((gcompg(cp->cOrderPlus, c) != 1) || (gcompg(cp->cOrderPlus, d) != 1) || isZero(c) || isZero(d)) { returnGiant(c); returnGiant(d); return FR_InvalidSignature; } /* * W = signer's public key */ W = feePubKeyPlusCurve(pubKey); /* * 1) Compute h = d^(-1) (mod x1OrderPlus); */ SIGPROF_START; h = borrowGiant(cp->maxDigits); gtog(d, h); binvg_x1OrderPlus(cp, h); SIGPROF_END(vfyStep1); /* * 2) h1 = digest as giant (skips assigning to 'f' in P1363) */ if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { h1 = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { h1 = borrowGiant(cp->maxDigits); } deserializeGiant(data, h1, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, h1); } sigLogGiant(" Wx : ", W->x); sigLogGiant(" f : ", h1); sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); sigLogGiant(" s^(-1) : ", h); /* * 3) Compute h1 = f * h mod x1OrderPlus; */ SIGPROF_START; mulg(h, h1); // h1 := f * h x1OrderPlusMod(h1, cp); SIGPROF_END(vfyStep3); /* * 4) Compute h2 = c * h (mod x1OrderPlus); */ SIGPROF_START; h2 = borrowGiant(cp->maxDigits); gtog(c, h2); mulg(h, h2); // h2 := c * h x1OrderPlusMod(h2, cp); SIGPROF_END(vfyStep4); /* * 5) Compute h2W = h2 'o' W (W = theirPub) */ CKASSERT((W->y != NULL) && !isZero(W->y)); h2W = newPointProj(cp->maxDigits); gtog(W->x, h2W->x); gtog(W->y, h2W->y); int_to_giant(1, h2W->z); ellMulProjSimple(h2W, h2, cp); /* * 6) Compute h1G = h1 'o' G (G = {x1Plus, y1Plus, 1} ) */ CKASSERT((cp->y1Plus != NULL) && !isZero(cp->y1Plus)); h1G = newPointProj(cp->maxDigits); gtog(cp->x1Plus, h1G->x); gtog(cp->y1Plus, h1G->y); int_to_giant(1, h1G->z); ellMulProjSimple(h1G, h1, cp); /* * 7) h1G := (h1 'o' G) + (h2 'o' W) */ ellAddProj(h1G, h2W, cp); /* * 8) If elliptic sum is point at infinity, signature is bad; stop. */ if(isZero(h1G->z)) { dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n")); result = 1; goto vfyDone; } normalizeProj(h1G, cp); /* * 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus */ cPrime = borrowGiant(cp->maxDigits); gtog(h1G->x, cPrime); x1OrderPlusMod(cPrime, cp); /* * 10) Good sig iff cPrime == c */ result = gcompg(c, cPrime); vfyDone: if(result) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } returnGiant(c); returnGiant(d); returnGiant(h); returnGiant(h1); returnGiant(h2); if(h1G != NULL) { freePointProj(h1G); } if(h2W != NULL) { freePointProj(h2W); } if(cPrime != NULL) { returnGiant(cPrime); } return frtn; }
feeReturn feeECDSASign( feePubKey pubKey, feeSigFormat format, // Signature format DER 9.62 / RAW const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feeRandFcn randFcn, // optional void *randRef, // optional unsigned char **sigData, // malloc'd and RETURNED unsigned *sigDataLen) // RETURNED { curveParams *cp; /* giant integers per IEEE P1363 notation */ giant c; // both 1363 'c' and 'i' // i.e., x-coord of u's pub key giant d; giant u; // random private key giant s; // private key as giant giant f; // data (message) as giant feeReturn frtn = FR_Success; feeRand frand; unsigned char *randBytes; unsigned randBytesLen; unsigned groupBytesLen; giant privGiant; #if ECDSA_SIGN_USE_PROJ pointProjStruct pt; // pt->x = c giant pty; // pt->y giant ptz; // pt->z #endif // ECDSA_SIGN_USE_PROJ if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } if(cp->curveType != FCT_Weierstrass) { return FR_IllegalCurve; } CKASSERT(!isZero(cp->x1OrderPlus)); /* * Private key and message to be signed as giants */ privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); return FR_IllegalArg; } s = borrowGiant(cp->maxDigits); gtog(privGiant, s); if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { f = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { f = borrowGiant(cp->maxDigits); } deserializeGiant(data, f, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, f); } sigDbg(("ECDSA sign:\n")); sigLogGiant(" s : ", s); sigLogGiant(" f : ", f); c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); u = borrowGiant(cp->maxDigits); if(randFcn == NULL) { frand = feeRandAlloc(); } else { frand = NULL; } /* * Random size is just larger than base prime */ groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); randBytesLen = groupBytesLen+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits" randBytes = (unsigned char*) fmalloc(randBytesLen); #if ECDSA_SIGN_USE_PROJ /* quick temp pointProj */ pty = borrowGiant(cp->maxDigits); ptz = borrowGiant(cp->maxDigits); pt.x = c; pt.y = pty; pt.z = ptz; #endif // ECDSA_SIGN_USE_PROJ while(1) { /* Repeat this loop until we have a non-zero c and d */ /* * 1) Obtain random u in [2, x1OrderPlus-2] */ SIGPROF_START; if(randFcn) { randFcn(randRef, randBytes, randBytesLen); } else { feeRandBytes(frand, randBytes, randBytesLen); } deserializeGiant(randBytes, u, randBytesLen); sigLogGiant(" raw u : ", u); sigLogGiant(" order : ", cp->x1OrderPlus); x1OrderPlusJustify(u, cp); SIGPROF_END(signStep1); sigLogGiant(" in range u : ", u); /* * note 'o' indicates elliptic multiply, * is integer mult. * * 2) Compute x coordinate, call it c, of u 'o' G * 3) Reduce: c := c mod x1OrderPlus; * 4) If c == 0, goto (1); */ SIGPROF_START; gtog(cp->x1Plus, c); #if ECDSA_SIGN_USE_PROJ /* projective coordinates */ gtog(cp->y1Plus, pty); int_to_giant(1, ptz); ellMulProjSimple(&pt, u, cp); #else /* ECDSA_SIGN_USE_PROJ */ /* the FEE way */ elliptic_simple(c, u, cp); #endif /* ECDSA_SIGN_USE_PROJ */ SIGPROF_END(signStep2); SIGPROF_START; x1OrderPlusMod(c, cp); SIGPROF_END(signStep34); if(isZero(c)) { dbgLog(("feeECDSASign: zero modulo (1)\n")); continue; } /* * 5) Compute u^(-1) mod x1OrderPlus; */ SIGPROF_START; gtog(u, d); binvg_x1OrderPlus(cp, d); SIGPROF_END(signStep5); sigLogGiant(" u^(-1) : ", d); /* * 6) Compute signature d as: * d = [u^(-1) (f + s*c)] (mod x1OrderPlus) */ SIGPROF_START; mulg(c, s); // s *= c x1OrderPlusMod(s, cp); addg(f, s); // s := f + (s * c) x1OrderPlusMod(s, cp); mulg(s, d); // d := u^(-1) (f + (s * c)) x1OrderPlusMod(d, cp); SIGPROF_END(signStep67); /* * 7) If d = 0, goto (1); */ if(isZero(d)) { dbgLog(("feeECDSASign: zero modulo (2)\n")); continue; } sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); break; // normal successful exit } /* * 8) signature is now the integer pair (c, d). */ /* * Cook up raw data representing the signature. */ SIGPROF_START; ECDSA_encode(format,groupBytesLen, c, d, sigData, sigDataLen); SIGPROF_END(signStep8); if(frand != NULL) { feeRandFree(frand); } ffree(randBytes); returnGiant(u); returnGiant(d); returnGiant(c); returnGiant(f); returnGiant(s); #if ECDSA_SIGN_USE_PROJ returnGiant(pty); returnGiant(ptz); #endif /* ECDSA_SIGN_USE_PROJ */ return frtn; }