/* * Alloc and init a feeFEEDExp object associated with specified feePubKey. */ feeFEEDExp feeFEEDExpNewWithPubKey( feePubKey pubKey, feeRandFcn randFcn, // optional void *randRef) { feedInst *finst = (feedInst *) fmalloc(sizeof(feedInst)); giant privGiant; finst->cp = curveParamsCopy(feePubKeyCurveParams(pubKey)); finst->plus = new_public_with_key(feePubKeyPlusCurve(pubKey), finst->cp); finst->minus = new_public_with_key(feePubKeyMinusCurve(pubKey), finst->cp); /* * These might yield NULL data; we can only encrypt in that case. */ privGiant = feePubKeyPrivData(pubKey); if(privGiant) { finst->gPriv = newGiant(finst->cp->maxDigits); gtog(privGiant, finst->gPriv); } else { finst->gPriv = NULL; } /* * Conservative, rounding down, on plaintext blocks since we don't * want to split bytes. */ if(finst->cp->primeType == FPT_General) { unsigned blen = bitlen(finst->cp->basePrime); finst->plainBlockSize = blen / 8; if((blen % 8) == 0) { /* * round down some more... */ finst->plainBlockSize--; } } else { finst->plainBlockSize = finst->cp->q / 8; if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) { /* * Special case, with q mod 8 == 0. Here we have to trim back * the plainBlockSize by one byte. */ finst->plainBlockSize--; } } /* * One block of ciphertext - two giants (with implied sign) and a * parity byte */ finst->cipherBlockSize = (2 * finst->cp->minBytes) + 1; finst->xp = newGiant(finst->cp->maxDigits); finst->xc = newGiant(finst->cp->maxDigits); finst->xq = newGiant(finst->cp->maxDigits); finst->xm = newGiant(finst->cp->maxDigits); finst->xaux = newGiant(finst->cp->maxDigits); finst->rand = NULL; finst->randData = NULL; finst->randFcn = randFcn; finst->randRef = randRef; return finst; }
/* * FEE_SIG_USING_PROJ true : this is the "no Weierstrass" case * feeSigVerifyNoProj false : this is redefined to feeSigVerify */ feeReturn feeSigVerifyNoProj(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { giant Q = NULL; giant messageGiant = NULL; giant scratch = NULL; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); frtn = FR_IllegalArg; goto out; } cp = feePubKeyCurveParams(pubKey); Q = newGiant(cp->maxDigits); /* * pick a key (+/-) * Q := P1 */ if(SIG_CURVE == CURVE_PLUS) { origKey = feePubKeyPlusCurve(pubKey); gtog(cp->x1Plus, Q); } else { origKey = feePubKeyMinusCurve(pubKey); gtog(cp->x1Minus, Q); } messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ elliptic_simple(Q, sinst->u, cp); /* scratch := theirPub */ scratch = newGiant(cp->maxDigits); gtog(origKey->x, scratch); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ elliptic_simple(scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch); } #endif // SIG_DEBUG if(signature_compare(Q, sinst->PmX, scratch, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } out: if(messageGiant != NULL) { freeGiant(messageGiant); } if(Q != NULL) { freeGiant(Q); } if(scratch != NULL) { freeGiant(scratch); } return frtn; }
/* * Alloc and init a feeFEED object associated with specified public and * private keys. */ feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey, feePubKey theirPubKey, int forEncrypt, // 0 ==> decrypt 1 ==> encrypt feeRandFcn randFcn, // optional void *randRef) { feedInst *finst; giant privGiant; key k; unsigned expPlainSize; unsigned expCipherSize; unsigned expBlocks; if(!curveParamsEquivalent(feePubKeyCurveParams(theirPubKey), feePubKeyCurveParams(myPrivKey))) { dbgLog(("feeFEEDNewWithPubKey: Incompatible Keys\n")); return NULL; } finst = (feedInst*) fmalloc(sizeof(feedInst)); bzero(finst, sizeof(feedInst)); finst->forEncrypt = forEncrypt; finst->cp = curveParamsCopy(feePubKeyCurveParams(theirPubKey)); finst->rsBlockCount = 0; finst->xp = newGiant(finst->cp->maxDigits); finst->xm = newGiant(finst->cp->maxDigits); finst->tmp1 = newGiant(finst->cp->maxDigits); if(forEncrypt) { finst->tmp2 = newGiant(finst->cp->maxDigits); } /* * cluePlus = ourPriv * theirPub+ * clueMinus = ourPriv * theirPub- */ finst->cluePlus = newGiant(finst->cp->maxDigits); finst->clueMinus = newGiant(finst->cp->maxDigits); privGiant = feePubKeyPrivData(myPrivKey); if(privGiant == NULL) { dbgLog(("feeFEEDNewWithPubKey: no private key\n")); goto abort; } k = feePubKeyPlusCurve(theirPubKey); gtog(k->x, finst->cluePlus); // cluePlus = theirPub+ elliptic_simple(finst->cluePlus, privGiant, finst->cp); k = feePubKeyMinusCurve(theirPubKey); gtog(k->x, finst->clueMinus); // theirPub- elliptic_simple(finst->clueMinus, privGiant, finst->cp); /* * Set up block sizes. */ if(finst->cp->primeType == FPT_General) { unsigned blen = bitlen(finst->cp->basePrime); finst->plainBlockSize = blen / 8; if((blen & 0x7) == 0) { /* * round down some more... */ finst->plainBlockSize--; } } else { finst->plainBlockSize = finst->cp->q / 8; if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) { /* * Special case, with q mod 8 == 0. Here we have to * trim back the plainBlockSize by one byte. */ finst->plainBlockSize--; } } finst->cipherBlockSize = finst->cp->minBytes + 1; /* * the size of initialRS is subject to tweaking - if we make it * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock * in our ciphertext. */ finst->initialRSSize = finst->plainBlockSize * 2; if(finst->initialRSSize > RS_MIN_SIZE) { unsigned minPlainBlocks; unsigned maxSize; /* * How many plainblocks to hold RS_MIN_SIZE? */ minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) / finst->plainBlockSize; /* * Max size = that many plainblocks, less 2 bytes (to avoid * extra residue block). */ maxSize = minPlainBlocks * finst->plainBlockSize - 2; /* * But don't bother with more than 2 plainblocks worth */ if(finst->initialRSSize > maxSize) { finst->initialRSSize = maxSize; } } /* else leave it alone, that's small enough */ if(forEncrypt) { feeRand frand = NULL; /* * Encrypt-capable FEEDExp object */ finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey, randFcn, randRef); if(finst->feedExp == NULL) { goto abort; } /* * Generate initial r and s data. */ finst->initialRS = (unsigned char*) fmalloc(finst->initialRSSize); if(randFcn != NULL) { randFcn(randRef, finst->initialRS, finst->initialRSSize); } else { frand = feeRandAlloc(); feeRandBytes(frand, finst->initialRS, finst->initialRSSize); feeRandFree(frand); } if(initFromRS(finst)) { goto abort; } } else { /* * Decrypt-capable FEEDExp object */ finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey, randFcn, randRef); if(finst->feedExp == NULL) { goto abort; } } /* * Figure out how many of our cipherblocks it takes to hold * a FEEDExp-encrypted initialRS. If initialRSSize is an exact * multiple of expPlainSize, we get an additional feedExp * residue block. */ expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp); expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp); expBlocks = (finst->initialRSSize + expPlainSize - 1) / expPlainSize; if((finst->initialRSSize % expPlainSize) == 0) { expBlocks++; } /* * Total meaningful bytes of encrypted initialRS */ finst->rsCtextSize = expBlocks * expCipherSize; /* * Number of our cipherblocks it takes to hold rsCtextSize */ finst->rsSizeCipherBlocks = (finst->rsCtextSize + finst->cipherBlockSize - 1) / finst->cipherBlockSize; if(!forEncrypt) { finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks * finst->cipherBlockSize); } /* * Sanity check... */ #if FEED_DEBUG { unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp); /* * FEEDExp has one more giant in ciphertext, plaintext is * same size */ if((finst->cipherBlockSize + finst->cp->minBytes) != fexpBlockSize) { dbgLog(("feeFEEDNewWithPubKey: FEEDExp CBlock Size " "screwup\n")); goto abort; } fexpBlockSize = feeFEEDExpPlainBlockSize(finst->feedExp); if(fexpBlockSize != finst->plainBlockSize) { dbgLog(("feeFEEDNewWithPubKey: FEEDExp PBlock Size " "screwup\n")); goto abort; } } #endif // FEED_DEBUG return finst; abort: feeFEEDFree(finst); return NULL; }
feeReturn feeSigVerify(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { pointProjStruct Q; giant messageGiant = NULL; pointProjStruct scratch; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); return FR_IllegalArg; } cp = feePubKeyCurveParams(pubKey); if(cp->curveType != FCT_Weierstrass) { return feeSigVerifyNoProj(sig, data, dataLen, pubKey); } borrowPointProj(&Q, cp->maxDigits); borrowPointProj(&scratch, cp->maxDigits); /* * Q := P1 */ gtog(cp->x1Plus, Q.x); gtog(cp->y1Plus, Q.y); int_to_giant(1, Q.z); messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ ellMulProjSimple(&Q, sinst->u, cp); /* scratch := theirPub */ origKey = feePubKeyPlusCurve(pubKey); gtog(origKey->x, scratch.x); gtog(origKey->y, scratch.y); int_to_giant(1, scratch.z); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ ellMulProjSimple(&scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q.x); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch.x); } #endif // SIG_DEBUG if(signature_compare(Q.x, sinst->PmX, scratch.x, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } freeGiant(messageGiant); returnPointProj(&Q); returnPointProj(&scratch); return frtn; }
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; }