/* * 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; }