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;

}
Beispiel #2
0
/*
 * 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;
}