feeReturn createFEED(feePubKey sendPrivKey, // required feePubKey recvPubKey, const unsigned char *plainText, unsigned plainTextLen, int genSig, // 1 ==> generate signature unsigned userData, // for caller's convenience feeCipherFile *cipherFile) // RETURNED if successful { feeReturn frtn; feeFEED feed = NULL; unsigned char *cipherText = NULL; unsigned cipherTextLen; unsigned char *sigData = NULL; unsigned sigDataLen = 0; feeCipherFile cfile = NULL; unsigned char *pubKeyString = NULL; // of sendPrivKey unsigned pubKeyStringLen = 0; if((sendPrivKey == NULL) || (recvPubKey == NULL)) { return FR_BadPubKey; } /* * FEED encrypt plaintext */ feed = feeFEEDNewWithPubKey(sendPrivKey, recvPubKey, FF_ENCRYPT, NULL, NULL); if(feed == NULL) { frtn = FR_BadPubKey; goto out; } frtn = feeFEEDEncrypt(feed, plainText, plainTextLen, &cipherText, &cipherTextLen); if(frtn) { goto out; } /* * Sender's public key string */ frtn = feePubKeyCreateKeyString(sendPrivKey, (char **)&pubKeyString, &pubKeyStringLen); if(frtn) { /* * Huh? */ frtn = FR_BadPubKey; goto out; } if(genSig) { /* * We generate signature on ciphertext by convention. */ frtn = feePubKeyCreateSignature(sendPrivKey, cipherText, cipherTextLen, &sigData, &sigDataLen); if(frtn) { goto out; } } /* * Cons up a cipherfile */ cfile = feeCFileNewFromCipherText(CFE_FEED, cipherText, cipherTextLen, pubKeyString, pubKeyStringLen, NULL, 0, sigData, sigDataLen, userData); if(cfile == NULL) { frtn = FR_Internal; goto out; } out: /* free alloc'd stuff */ if(cipherText) { ffree(cipherText); } if(feed) { feeFEEDFree(feed); } if(pubKeyString) { ffree(pubKeyString); } if(sigData) { ffree(sigData); } *cipherFile = cfile; 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 decryptFEED(feeCipherFile cipherFile, feePubKey recvPrivKey, feePubKey sendPubKey, // optional unsigned char **plainText, // RETURNED unsigned *plainTextLen, // RETURNED feeSigStatus *sigStatus) // RETURNED { feeReturn frtn = FR_Success; unsigned char *cipherText = NULL; unsigned cipherTextLen; feeFEED feed = NULL; unsigned char *sigData = NULL; unsigned sigDataLen; unsigned char *sendPubKeyStr = NULL; unsigned sendPubKeyStrLen = 0; feePubKey parsedSendPubKey = NULL; if(feeCFileEncrType(cipherFile) != CFE_FEED) { frtn = FR_Internal; goto out; } //printf("decryptFEED\n"); //printf("privKey:\n"); printPubKey(recvPrivKey); //printf("pubKey:\n"); printPubKey(sendPubKey); /* * Get ciphertext and sender's public key from cipherFile */ cipherText = feeCFileCipherText(cipherFile, &cipherTextLen); if(cipherText == NULL) { frtn = FR_BadCipherFile; goto out; } sendPubKeyStr = feeCFileSendPubKeyData(cipherFile, &sendPubKeyStrLen); if(sendPubKeyStr == NULL) { frtn = FR_BadCipherFile; goto out; } parsedSendPubKey = feePubKeyAlloc(); frtn = feePubKeyInitFromKeyString(parsedSendPubKey, (char *)sendPubKeyStr, sendPubKeyStrLen); if(frtn) { frtn = FR_BadCipherFile; goto out; } //printf("parsedSendPubKey:\n"); printPubKey(parsedSendPubKey); /* * FEED decrypt */ feed = feeFEEDNewWithPubKey(recvPrivKey, parsedSendPubKey, FF_DECRYPT, NULL, NULL); if(feed == NULL) { frtn = FR_BadPubKey; goto out; } frtn = feeFEEDDecrypt(feed, cipherText, cipherTextLen, plainText, plainTextLen); if(frtn) { goto out; } sigData = feeCFileSigData(cipherFile, &sigDataLen); if(sigData) { feeReturn sigFrtn; if(sendPubKey == NULL) { /* * use embedded sender's public key */ sendPubKey = parsedSendPubKey; } sigFrtn = feePubKeyVerifySignature(sendPubKey, cipherText, cipherTextLen, sigData, sigDataLen); switch(sigFrtn) { case FR_Success: *sigStatus = SS_PresentValid; break; default: *sigStatus = SS_PresentInvalid; break; } } else { *sigStatus = SS_NotPresent; } out: if(cipherText) { ffree(cipherText); } if(feed) { feeFEEDFree(feed); } if(sigData) { ffree(sigData); } if(parsedSendPubKey) { feePubKeyFree(parsedSendPubKey); } if(sendPubKeyStr) { ffree(sendPubKeyStr); } return frtn; }