Example #1
0
/*
 * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
 * generates feeFEEDPlainBlockSize of plaintext, unless finalBlock is
 * non-zero (in which case feeFEEDPlainBlockSize or less bytes of plainText are
 * generated).
 */
feeReturn feeFEEDDecryptBlock(feeFEED feed,
	const unsigned char *cipherText,
	unsigned cipherTextLen,
	unsigned char *plainText,
	unsigned *plainTextLen,			// RETURNED
	int finalBlock)
{
	feedInst 	*finst = (feedInst *) feed;
	feeReturn	frtn = FR_Success;
	unsigned char	clueByte;
	giant		thisClue;		// not alloc'd
	giant		thisS;			// ditto
	int 		parity;

	if(finst->rsCtext == NULL) {
		/*
		 * Init'd for encrypt?
		 */
		return FR_IllegalArg;
	}
	if(cipherTextLen != finst->cipherBlockSize) {
	 	dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n"));
		return FR_IllegalArg;
	}
	if(finst->rsBlockCount < finst->rsSizeCipherBlocks) {
		/*
		 * Processing initialRS, FEEDExp-encrypted
		 */
		unsigned char *rsPtr = finst->rsCtext +
			(finst->rsBlockCount * finst->cipherBlockSize);
		unsigned feedExpCipherSize;

		if(finalBlock) {
		    dbgLog(("feeFEEDDecryptBlock: incomplete initialRS\n"));
		    return FR_BadCipherText;
		}
		bcopy(cipherText, rsPtr, finst->cipherBlockSize);
		finst->rsBlockCount++;
		if(finst->rsBlockCount < finst->rsSizeCipherBlocks) {
		    /*
		     * Not done with this yet...
		     */
			bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (1)\n", 
				cipherTextLen));
		    *plainTextLen = 0;
		    return FR_Success;
		}

		#if	FEED_DEBUG
		if((finst->rsBlockCount * finst->cipherBlockSize) <
				finst->rsCtextSize) {
		    dbgLog(("feeFEEDDecryptBlock: rsCtextSize underflow!\n"));
		    return FR_Internal;
		}
		#endif	// FEED_DEBUG

		/*
		 * OK, we should have the FEEDExp ciphertext for initialRS
		 * in rsCtext. Note the last few bytes are extra; we don't
		 * pass them to FEEDExp.
		 */
		feedExpCipherSize = feeFEEDCipherBlockSize(finst->feedExp);
		frtn = feeFEEDExpDecrypt(finst->feedExp,
			finst->rsCtext,
			finst->rsCtextSize,
			&finst->initialRS,
			&finst->initialRSSize);
		if(frtn) {
   		    dbgLog(("feeFEEDDecryptBlock: error decrypting "
		    	"initialRS (%s)\n", feeReturnString(frtn)));
		    return FR_BadCipherText;
		}

		/*
		 * we already know how long this should be...
		 */
		if(finst->initialRSSize != finst->initialRSSize) {
   		    dbgLog(("feeFEEDDecryptBlock: initialRS sync error\n"));
		    return FR_BadCipherText;
		}

		/*
		 * Set up clues
		 */
		if(initFromRS(finst)) {
   		    dbgLog(("feeFEEDDecryptBlock: bad initialRS\n"));
		    return FR_BadCipherText;
		}
		else {
		    /*
		     * Normal completion of last cipherblock containing
		     * initialRS.
		     */
			bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n", 
				cipherTextLen));
		    *plainTextLen = 0;
		    return FR_Success;
		}
	}

	/*
	 * grab xm and clueByte from cipherText
	 */
	deserializeGiant(cipherText, finst->xm, finst->cp->minBytes);
	cipherText += finst->cp->minBytes;
	clueByte = *cipherText;

	if((clueByte & CLUE_BIT) == CLUE_PLUS) {
		thisClue = finst->cluePlus;
		thisS = finst->sPlus;
	}
	else {
		thisClue = finst->clueMinus;
		thisS = finst->sMinus;
	}
	if((clueByte & PARITY_BIT) == PARITY_PLUS) {
		parity = SIGN_PLUS;
	}
	else {
		parity = SIGN_MINUS;
	}

	/*
	 * recover xp
	 *     xp = xm + clue(+/-) w/parity
	 * adjust clue
	 *     clue[n+1] = r * clue[n] + (s * P1)
	 */
	elliptic_add(thisClue, finst->xm, finst->xp, finst->cp, parity);

	elliptic_simple(thisClue, finst->r, finst->cp);
	gtog(thisClue, finst->tmp1);
	elliptic_add(finst->tmp1, thisS, thisClue, finst->cp, SIGN_PLUS);

	/*
	 * plaintext in xp
	 */
	#if	FEED_DEBUG
	printf("decrypt  clue %d\n", clueByte);
	printf("  xp : "); printGiant(finst->xp);
	printf("  xm : "); printGiant(finst->xm);
	printf("  cluePlus  :"); printGiant(finst->cluePlus);
	printf("  clueMinus :"); printGiant(finst->clueMinus);
	#endif	// FEED_DEBUG

	if(finalBlock) {
		/*
		 * Snag data from xp in order to find out how much to move to
		 * *plainText
		 */
		unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize);

		serializeGiant(finst->xp, ptext, finst->plainBlockSize);
		*plainTextLen = ptext[finst->plainBlockSize - 1];
		if(*plainTextLen == RESID_ZERO) {
			bprintf(("=== FEED Decrypt: RESID_ZERO\n"));
			*plainTextLen = 0;
		}
		else if(*plainTextLen > (finst->plainBlockSize - 1)) {
			dbgLog(("feeFEEDDecryptBlock: ptext overflow!\n"));
			bprintf(("feeFEEDDecryptBlock: ptext overflow!\n"));
			frtn = FR_BadCipherText;
		}
		else {
			bprintf(("=== FEED Decrypt: resid len 0x%x\n", *plainTextLen));
			bcopy(ptext, plainText, *plainTextLen);
		}
		ffree(ptext);
	}
	else {
		*plainTextLen = finst->plainBlockSize;
		serializeGiant(finst->xp, plainText, *plainTextLen);
	}
	bprintf(("=== FEED decryptBlock ptextLen 0x%x  ctextLen 0x%x\n",
		*plainTextLen, cipherTextLen));

	return frtn;
}
feeReturn decryptFEEDExp(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;
	feeFEEDExp	feed = NULL;
	unsigned char	*sigData = NULL;
	unsigned	sigDataLen;
	unsigned char	*sendPubKeyStr = NULL;
	unsigned	sendPubKeyStrLen = 0;
	feePubKey 	parsedSendPubKey = NULL;

	if(feeCFileEncrType(cipherFile) != CFE_FEEDExp) {
		frtn = FR_Internal;
		goto out;
	}

	/*
	 * Get ciphertext from cipherFile
	 */
	cipherText = feeCFileCipherText(cipherFile, &cipherTextLen);
	if(cipherText == NULL) {
		frtn = FR_BadCipherFile;
		goto out;
	}

	/*
	 * FEEDExp decrypt
	 */
	feed = feeFEEDExpNewWithPubKey(recvPrivKey, NULL, NULL);
	if(feed == NULL) {
		frtn = FR_BadPubKey;
		goto out;
	}
	frtn = feeFEEDExpDecrypt(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
			 */
			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;
			}
			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) {
		feeFEEDExpFree(feed);
	}
	if(sigData) {
		ffree(sigData);
	}
	if(parsedSendPubKey) {
		feePubKeyFree(parsedSendPubKey);
	}
	if(sendPubKeyStr) {
		ffree(sendPubKeyStr);
	}
	return frtn;
}