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; }
/* * Create new feeSig object, including a random large integer 'randGiant' for * possible use in salting a feeHash object, and 'PmX', equal to * randGiant 'o' P1. Note that this is not called when *verifying* a * signature, only when signing. */ feeSig feeSigNewWithKey( feePubKey pubKey, feeRandFcn randFcn, /* optional */ void *randRef) { sigInst *sinst = sinstAlloc(); feeRand frand; unsigned char *randBytes; unsigned randBytesLen; curveParams *cp; if(pubKey == NULL) { return NULL; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return NULL; } /* * Generate random m, a little larger than key size, save as randGiant */ randBytesLen = (feePubKeyBitsize(pubKey) / 8) + 1; randBytes = (unsigned char*) fmalloc(randBytesLen); if(randFcn) { randFcn(randRef, randBytes, randBytesLen); } else { frand = feeRandAlloc(); feeRandBytes(frand, randBytes, randBytesLen); feeRandFree(frand); } sinst->randGiant = giant_with_data(randBytes, randBytesLen); memset(randBytes, 0, randBytesLen); ffree(randBytes); #if FEE_DEBUG if(isZero(sinst->randGiant)) { printf("feeSigNewWithKey: randGiant = 0!\n"); } #endif // FEE_DEBUG /* * Justify randGiant to be in [2, x1OrderPlus] */ x1OrderPlusJustify(sinst->randGiant, cp); /* PmX := randGiant 'o' P1 */ sinst->PmX = newGiant(cp->maxDigits); #if CRYPTKIT_ELL_PROJ_ENABLE if(cp->curveType == FCT_Weierstrass) { pointProjStruct pt0; sinst->PmY = newGiant(cp->maxDigits); /* cook up pt0 as P1 */ pt0.x = sinst->PmX; pt0.y = sinst->PmY; pt0.z = borrowGiant(cp->maxDigits); gtog(cp->x1Plus, pt0.x); gtog(cp->y1Plus, pt0.y); int_to_giant(1, pt0.z); /* pt0 := P1 'o' randGiant */ ellMulProjSimple(&pt0, sinst->randGiant, cp); returnGiant(pt0.z); } else { if(SIG_CURVE == CURVE_PLUS) { gtog(cp->x1Plus, sinst->PmX); } else { gtog(cp->x1Minus, sinst->PmX); } elliptic_simple(sinst->PmX, sinst->randGiant, cp); } #else /* CRYPTKIT_ELL_PROJ_ENABLE */ if(SIG_CURVE == CURVE_PLUS) { gtog(cp->x1Plus, sinst->PmX); } else { gtog(cp->x1Minus, sinst->PmX); } elliptic_simple(sinst->PmX, sinst->randGiant, cp); #endif /* CRYPTKIT_ELL_PROJ_ENABLE */ return sinst; }
/* * 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; }
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; }
/* * Sign specified block of data (most likely a hash result) using * specified feePubKey. */ feeReturn feeSigSign(feeSig sig, const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feePubKey pubKey) { sigInst *sinst = (sigInst*) sig; giant messageGiant = NULL; unsigned maxlen; giant privGiant; unsigned privGiantBytes; feeReturn frtn = FR_Success; unsigned randBytesLen; unsigned uDigits; // alloc'd digits in sinst->u curveParams *cp; if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); frtn = FR_IllegalArg; goto abort; } privGiantBytes = abs(privGiant->sign) * GIANT_BYTES_PER_DIGIT; /* * Note PmX = m 'o' P1. * Get message/digest as giant. May be significantly different * in size from pubKey's basePrime. */ messageGiant = giant_with_data(data, dataLen); // M(text) randBytesLen = feePubKeyBitsize(pubKey) / 8; maxlen = max(randBytesLen, dataLen); /* leave plenty of room.... */ uDigits = (3 * (privGiantBytes + maxlen)) / GIANT_BYTES_PER_DIGIT; sinst->u = newGiant(uDigits); gtog(privGiant, sinst->u); // u := ourPri mulg(messageGiant, sinst->u); // u *= M(text) addg(sinst->randGiant, sinst->u); // u += m /* * Paranoia: we're using the curveParams from the caller's pubKey; * this cp will have a valid x1OrderPlusRecip if pubKey is the same * as the one passed to feeSigNewWithKey() (since feeSigNewWithKey * called x1OrderPlusJustify()). But the caller could conceivably be * using a different instance of their pubKey, in which case * the key's cp->x1OrderPlusRecip may not be valid. */ calcX1OrderPlusRecip(cp); /* u := u mod x1OrderPlus */ #if SIG_DEBUG if(sigDebug) { printf("sigSign:\n"); printf("u pre-modg : "); printGiant(sinst->u); } #endif modg_via_recip(cp->x1OrderPlus, cp->x1OrderPlusRecip, sinst->u); #if SIG_DEBUG if(sigDebug) { printf("privGiant : "); printGiant(privGiant); printf("u : "); printGiant(sinst->u); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams :\n"); printCurveParams(cp); } #endif // SIG_DEBUG abort: if(messageGiant) { freeGiant(messageGiant); } return frtn; }
/* * cons up: * cluePlus(0) * clueMinus(0) * sPlus * sMinus * r * Assumes: * cluePlus = clueMinus = ourPriv * theirPub * initialRS * initialRSSize * cp * * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting * first block of data. */ static feeReturn initFromRS(feedInst *finst) { giant s; unsigned rSize = finst->initialRSSize / 2; #if FEED_DEBUG if((finst->initialRS == NULL) || (finst->cp == NULL) || (finst->cluePlus == NULL) || (finst->clueMinus == NULL) || (finst->initialRSSize == 0)) { dbgLog(("initFromRS: resource shortage\n")); return FR_Internal; } #endif // FEED_DEBUG finst->r = giant_with_data(finst->initialRS, rSize); s = giant_with_data(finst->initialRS+rSize, rSize); #if FEED_DEBUG if(isZero(finst->r)) { printf("initFromRS: r = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } if(isZero(s)) { printf("initFromRS: s = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } #endif // FEE_DEBUG /* * Justify r and s to be in [2, minimumX1Order]. */ lesserX1OrderJustify(finst->r, finst->cp); lesserX1OrderJustify(s, finst->cp); /* * sPlus = s * x1Plus * sMinus = s * x1Minus */ finst->sPlus = newGiant(finst->cp->maxDigits); finst->sMinus = newGiant(finst->cp->maxDigits); gtog(finst->cp->x1Plus, finst->sPlus); elliptic_simple(finst->sPlus, s, finst->cp); gtog(finst->cp->x1Minus, finst->sMinus); elliptic_simple(finst->sMinus, s, finst->cp); /* * And finally, the initial clues. They are currently set to * ourPriv * theirPub. */ #if FEED_DEBUG printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_EEBUG elliptic_simple(finst->cluePlus, finst->r, finst->cp); elliptic_simple(finst->clueMinus, finst->r, finst->cp); #if FEED_DEBUG printf("r : "); printGiant(finst->r); printf("s : "); printGiant(s); printf("sPlus : "); printGiant(finst->sPlus); printf("sMinus : "); printGiant(finst->sMinus); printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_DEBUG freeGiant(s); return FR_Success; }