#include "ckconfig.h"
#if CRYPTKIT_ASYMMETRIC_ENABLE
#include "feeTypes.h"
#include "feeFEED.h"
#include "feeFEEDExp.h"
#include "feePublicKey.h"
#include "feePublicKeyPrivate.h"
#include "elliptic.h"
#include "falloc.h"
#include "feeRandom.h"
#include "ckutilities.h"
#include "feeFunctions.h"
#include "platform.h"
#include "curveParams.h"
#include "feeDebug.h"
#include <stdlib.h>
#include <stdio.h>
#define FEED_DEBUG 0
#define BUFFER_DEBUG 0
#if BUFFER_DEBUG
#define bprintf(s) printf s
#else
#define bprintf(s)
#endif
#define RS_MIN_SIZE 16
typedef struct {
curveParams *cp;
giant cluePlus;
giant clueMinus;
giant sPlus;
giant sMinus;
giant r;
unsigned plainBlockSize;
unsigned cipherBlockSize;
unsigned char *initialRS;
unsigned initialRSSize;
feeFEEDExp feedExp;
unsigned char *rsCtext;
unsigned rsBlockCount;
int forEncrypt;
unsigned rsCtextSize;
unsigned rsSizeCipherBlocks;
giant xp;
giant xm;
giant tmp1;
giant tmp2;
} feedInst;
#define RESID_ZERO 0xff
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
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
lesserX1OrderJustify(finst->r, finst->cp);
lesserX1OrderJustify(s, finst->cp);
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);
#if FEED_DEBUG
printf("cluePlus : "); printGiant(finst->cluePlus);
printf("clueMinus: "); printGiant(finst->clueMinus);
#endif
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
freeGiant(s);
return FR_Success;
}
feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey,
feePubKey theirPubKey,
int forEncrypt, feeRandFcn randFcn, 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);
}
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); elliptic_simple(finst->cluePlus, privGiant, finst->cp);
k = feePubKeyMinusCurve(theirPubKey);
gtog(k->x, finst->clueMinus); elliptic_simple(finst->clueMinus, privGiant, finst->cp);
if(finst->cp->primeType == FPT_General) {
unsigned blen = bitlen(finst->cp->basePrime);
finst->plainBlockSize = blen / 8;
if((blen & 0x7) == 0) {
finst->plainBlockSize--;
}
}
else {
finst->plainBlockSize = finst->cp->q / 8;
if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
finst->plainBlockSize--;
}
}
finst->cipherBlockSize = finst->cp->minBytes + 1;
finst->initialRSSize = finst->plainBlockSize * 2;
if(finst->initialRSSize > RS_MIN_SIZE) {
unsigned minPlainBlocks;
unsigned maxSize;
minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) /
finst->plainBlockSize;
maxSize = minPlainBlocks * finst->plainBlockSize - 2;
if(finst->initialRSSize > maxSize) {
finst->initialRSSize = maxSize;
}
}
if(forEncrypt) {
feeRand frand = NULL;
finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey,
randFcn,
randRef);
if(finst->feedExp == NULL) {
goto abort;
}
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 {
finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey,
randFcn,
randRef);
if(finst->feedExp == NULL) {
goto abort;
}
}
expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp);
expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp);
expBlocks = (finst->initialRSSize + expPlainSize - 1) /
expPlainSize;
if((finst->initialRSSize % expPlainSize) == 0) {
expBlocks++;
}
finst->rsCtextSize = expBlocks * expCipherSize;
finst->rsSizeCipherBlocks = (finst->rsCtextSize +
finst->cipherBlockSize - 1) / finst->cipherBlockSize;
if(!forEncrypt) {
finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks *
finst->cipherBlockSize);
}
#if FEED_DEBUG
{
unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp);
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
return finst;
abort:
feeFEEDFree(finst);
return NULL;
}
void feeFEEDFree(feeFEED feed)
{
feedInst *finst = (feedInst*) feed;
if(finst->cp) {
freeCurveParams(finst->cp);
}
if(finst->initialRS) {
ffree(finst->initialRS);
}
if(finst->cluePlus) {
freeGiant(finst->cluePlus);
}
if(finst->clueMinus) {
freeGiant(finst->clueMinus);
}
if(finst->sPlus) {
freeGiant(finst->sPlus);
}
if(finst->sMinus) {
freeGiant(finst->sMinus);
}
if(finst->r) {
freeGiant(finst->r);
}
if(finst->feedExp) {
feeFEEDExpFree(finst->feedExp);
}
if(finst->rsCtext) {
ffree(finst->rsCtext);
}
if(finst->xp) {
freeGiant(finst->xp);
}
if(finst->xm) {
freeGiant(finst->xm);
}
if(finst->tmp1) {
freeGiant(finst->tmp1);
}
if(finst->tmp2) {
freeGiant(finst->tmp2);
}
ffree(finst);
}
unsigned feeFEEDPlainBlockSize(feeFEED feed)
{
feedInst *finst = (feedInst *) feed;
return finst->plainBlockSize;
}
unsigned feeFEEDCipherBlockSize(feeFEED feed)
{
feedInst *finst = (feedInst *) feed;
return finst->cipherBlockSize;
}
unsigned feeFEEDCipherBufSize(feeFEED feed,
int finalBlock)
{
feedInst *finst = (feedInst *) feed;
unsigned blocks = 1;
if(finst->rsBlockCount == 0) {
blocks += finst->rsSizeCipherBlocks;
}
if(finalBlock) {
blocks++;
}
bprintf(("$$$ feeFEEDCipherBufSize( %s, %s): rtn 0x%x\n",
finst->forEncrypt ? "encrypt" : "decrypt",
finalBlock ? " final" : "!final",
blocks * finst->cipherBlockSize));
return blocks * finst->cipherBlockSize;
}
unsigned feeFEEDCipherTextSize(feeFEED feed,
unsigned plainTextSize,
int finalBlock)
{
feedInst *finst = (feedInst *) feed;
unsigned blocks = (plainTextSize + finst->plainBlockSize - 1) /
finst->plainBlockSize;
if(finst->forEncrypt) {
if(finst->rsBlockCount == 0) {
blocks += finst->rsSizeCipherBlocks;
}
if(finalBlock) {
if((plainTextSize % finst->plainBlockSize) == 0) {
blocks++;
}
}
}
else {
#if BUFFER_DEBUG
if(finst->rsBlockCount > finst->rsSizeCipherBlocks) {
printf("******HEY! rsBlockCount overflow! (blockCount %d rsSize %d)\n",
finst->rsBlockCount, finst->rsSizeCipherBlocks);
}
#endif
blocks += (finst->rsSizeCipherBlocks - finst->rsBlockCount);
}
bprintf(("$$$ feeFEEDCipherTextSize(%s, %s, 0x%x): rtn 0x%x\n",
finst->forEncrypt ? "encrypt" : "decrypt",
finalBlock ? " final" : "!final",
plainTextSize, blocks * finst->cipherBlockSize));
return blocks * finst->cipherBlockSize;
}
unsigned feeFEEDPlainTextSize(feeFEED feed,
unsigned cipherTextSize,
int finalBlock) {
feedInst *finst = (feedInst *) feed;
unsigned cipherBlocks = (cipherTextSize + finst->cipherBlockSize - 1) /
finst->cipherBlockSize;
unsigned rsBlocksToGo = finst->rsSizeCipherBlocks - finst->rsBlockCount;
if(finst->forEncrypt) {
if(rsBlocksToGo >= cipherBlocks) {
return 0;
}
cipherBlocks -= rsBlocksToGo;
if(finalBlock) {
if(cipherBlocks) {
cipherBlocks--;
}
}
}
else {
if(rsBlocksToGo >= cipherBlocks) {
cipherBlocks = 1;
}
else {
cipherBlocks -= rsBlocksToGo;
}
}
bprintf(("$$$ feeFEEDPlainTextSize( %s, %s, 0x%x): rtn 0x%x\n",
finst->forEncrypt ? "encrypt" : "decrypt",
finalBlock ? " final" : "!final",
cipherTextSize, cipherBlocks * finst->plainBlockSize));
return cipherBlocks * finst->plainBlockSize;
}
#define CLUE_BIT 0x01
#define CLUE_PLUS 0x01
#define CLUE_MINUS 0x00
#define PARITY_BIT 0x02
#define PARITY_PLUS 0x02
#define PARITY_MINUS 0x00
feeReturn feeFEEDEncryptBlock(feeFEED feed,
const unsigned char *plainText,
unsigned plainTextLen,
unsigned char *cipherText,
unsigned *cipherTextLen, int finalBlock)
{
feedInst *finst = (feedInst *) feed;
unsigned ctextLen = 0;
feeReturn frtn = FR_Success;
int whichCurve;
giant thisClue; giant thisS; unsigned char clueByte;
if(plainTextLen > finst->plainBlockSize) {
return FR_IllegalArg;
}
if((plainTextLen < finst->plainBlockSize) && !finalBlock) {
return FR_IllegalArg;
}
if(finst->initialRS == NULL) {
return FR_IllegalArg;
}
if(finst->rsBlockCount == 0) {
unsigned char *thisCtext; unsigned padLen;
if(finst->initialRS == NULL) {
dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n"));
return FR_IllegalArg;
}
frtn = feeFEEDExpEncrypt(finst->feedExp,
finst->initialRS,
finst->initialRSSize,
&thisCtext,
&ctextLen);
if(frtn) {
dbgLog(("feeFEEDEncryptBlock: error writing encrypted"
" initialRS (%s)\n", feeReturnString(frtn)));
return FR_Internal;
}
bcopy(thisCtext, cipherText, ctextLen);
cipherText += ctextLen;
ffree(thisCtext);
finst->rsBlockCount = finst->rsSizeCipherBlocks;
padLen = finst->cipherBlockSize -
(ctextLen % finst->cipherBlockSize);
#if 0
if((ctextLen / finst->cipherBlockSize) != 5) {
dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (1)\n"));
return FR_Internal;
}
if(padLen != 3) {
dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (2)\n"));
return FR_Internal;
}
#endif
while(padLen) {
*cipherText++ = 0;
ctextLen++;
padLen--;
}
}
if(finalBlock) {
unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize);
bzero(ptext, finst->plainBlockSize);
if(plainTextLen) {
bcopy(plainText, ptext, plainTextLen);
}
if(plainTextLen < finst->plainBlockSize) {
if(plainTextLen == 0) {
ptext[finst->plainBlockSize - 1] = RESID_ZERO;
bprintf(("=== FEED encrypt: RESID_ZERO\n"));
}
else {
ptext[finst->plainBlockSize - 1] = plainTextLen;
bprintf(("=== FEED encrypt: resid len 0x%x\n", plainTextLen));
}
}
deserializeGiant(ptext, finst->xp, finst->plainBlockSize);
ffree(ptext);
}
else {
deserializeGiant(plainText, finst->xp, plainTextLen);
}
whichCurve = which_curve(finst->xp, finst->cp);
if(whichCurve == CURVE_PLUS) {
thisClue = finst->cluePlus;
thisS = finst->sPlus;
clueByte = CLUE_PLUS;
}
else {
thisClue = finst->clueMinus;
thisS = finst->sMinus;
clueByte = CLUE_MINUS;
}
elliptic_add(thisClue, finst->xp, finst->xm, finst->cp, SIGN_PLUS);
elliptic_add(finst->xm, thisClue, finst->tmp1, finst->cp, SIGN_PLUS);
elliptic_simple(thisClue, finst->r, finst->cp);
gtog(thisClue, finst->tmp2);
elliptic_add(finst->tmp2, thisS, thisClue, finst->cp, SIGN_PLUS);
if(gcompg(finst->tmp1, finst->xp) == 0) {
clueByte |= PARITY_PLUS;
}
serializeGiant(finst->xm, cipherText, finst->cp->minBytes);
cipherText += finst->cp->minBytes;
ctextLen += finst->cp->minBytes;
*cipherText++ = clueByte;
ctextLen++;
#if FEED_DEBUG
printf("encrypt 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
if(finalBlock && (plainTextLen == finst->plainBlockSize)) {
unsigned moreCipher;
frtn = feeFEEDEncryptBlock(feed,
NULL, 0, cipherText, &moreCipher,
1);
if(frtn == FR_Success) {
ctextLen += moreCipher;
}
}
bprintf(("=== FEED encryptBlock ptextLen 0x%x ctextLen 0x%x\n",
plainTextLen, ctextLen));
*cipherTextLen = ctextLen;
return frtn;
}
feeReturn feeFEEDDecryptBlock(feeFEED feed,
const unsigned char *cipherText,
unsigned cipherTextLen,
unsigned char *plainText,
unsigned *plainTextLen, int finalBlock)
{
feedInst *finst = (feedInst *) feed;
feeReturn frtn = FR_Success;
unsigned char clueByte;
giant thisClue; giant thisS; int parity;
if(finst->rsCtext == NULL) {
return FR_IllegalArg;
}
if(cipherTextLen != finst->cipherBlockSize) {
dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n"));
return FR_IllegalArg;
}
if(finst->rsBlockCount < finst->rsSizeCipherBlocks) {
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) {
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
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;
}
if(finst->initialRSSize != finst->initialRSSize) {
dbgLog(("feeFEEDDecryptBlock: initialRS sync error\n"));
return FR_BadCipherText;
}
if(initFromRS(finst)) {
dbgLog(("feeFEEDDecryptBlock: bad initialRS\n"));
return FR_BadCipherText;
}
else {
bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n",
cipherTextLen));
*plainTextLen = 0;
return FR_Success;
}
}
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;
}
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);
#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
if(finalBlock) {
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 feeFEEDEncrypt(feeFEED feed,
const unsigned char *plainText,
unsigned plainTextLen,
unsigned char **cipherText, unsigned *cipherTextLen) {
const unsigned char *ptext; unsigned ptextLen; unsigned thisPtextLen; unsigned char *ctext; unsigned ctextLen; unsigned char *ctextResult; unsigned ctextResultLen; unsigned char *ctextPtr;
unsigned ctextLenTotal; feeReturn frtn;
int finalBlock;
unsigned numBlocks;
unsigned plainBlockSize;
#if FEE_DEBUG
unsigned expectedCtextSize;
expectedCtextSize = feeFEEDCipherTextSize(feed, plainTextLen, 1);
#endif
if(plainTextLen == 0) {
dbgLog(("feeFEEDDecrypt: NULL plainText\n"));
return FR_IllegalArg;
}
ptext = plainText;
ptextLen = plainTextLen;
ctext = (unsigned char*) fmalloc(feeFEEDCipherBufSize(feed, 1));
plainBlockSize = feeFEEDPlainBlockSize(feed);
numBlocks = (plainTextLen + plainBlockSize - 1)/plainBlockSize;
ctextResultLen = feeFEEDCipherTextSize(feed, plainTextLen, 1);
ctextResult = (unsigned char*) fmalloc(ctextResultLen);
ctextPtr = ctextResult;
ctextLenTotal = 0;
while(1) {
if(ptextLen <= plainBlockSize) {
finalBlock = 1;
thisPtextLen = ptextLen;
}
else {
finalBlock = 0;
thisPtextLen = plainBlockSize;
}
frtn = feeFEEDEncryptBlock(feed,
ptext,
thisPtextLen,
ctext,
&ctextLen,
finalBlock);
if(frtn) {
dbgLog(("feeFEEDEncrypt: encrypt error: %s\n",
feeReturnString(frtn)));
break;
}
if(ctextLen == 0) {
dbgLog(("feeFEEDEncrypt: null ciphertext\n"));
frtn = FR_Internal;
break;
}
bcopy(ctext, ctextPtr, ctextLen);
ctextLenTotal += ctextLen;
if(ctextLenTotal > ctextResultLen) {
dbgLog(("feeFEEDEncrypt: ciphertext overflow\n"));
frtn = FR_Internal;
break;
}
if(finalBlock) {
break;
}
ctextPtr += ctextLen;
ptext += thisPtextLen;
ptextLen -= thisPtextLen;
}
ffree(ctext);
if(frtn) {
ffree(ctextResult);
*cipherText = NULL;
*cipherTextLen = 0;
}
else {
*cipherText = ctextResult;
*cipherTextLen = ctextLenTotal;
#if FEE_DEBUG
if(expectedCtextSize != ctextLenTotal) {
printf("feeFEEDEncrypt: feeFEEDCipherTextSize error!\n");
printf("ptext %d exp ctext %d actual ctext %d\n",
plainTextLen,
expectedCtextSize,
ctextLenTotal);
}
#endif }
return frtn;
}
feeReturn feeFEEDDecrypt(feeFEED feed,
const unsigned char *cipherText,
unsigned cipherTextLen,
unsigned char **plainText, unsigned *plainTextLen) {
const unsigned char *ctext;
unsigned ctextLen; unsigned char *ptext; unsigned ptextLen; unsigned char *ptextResult; unsigned char *ptextPtr;
unsigned ptextLenTotal; feeReturn frtn = FR_Success;
int finalBlock;
unsigned numBlocks;
unsigned plainBlockSize = feeFEEDPlainBlockSize(feed);
unsigned cipherBlockSize = feeFEEDCipherBlockSize(feed);
if(cipherTextLen % cipherBlockSize) {
dbgLog(("feeFEEDDecrypt: unaligned cipherText\n"));
return FR_BadCipherText;
}
if(cipherTextLen == 0) {
dbgLog(("feeFEEDDecrypt: NULL cipherText\n"));
return FR_BadCipherText;
}
ptext = (unsigned char*) fmalloc(plainBlockSize);
ctext = cipherText;
ctextLen = cipherTextLen;
numBlocks = cipherTextLen / cipherBlockSize;
ptextResult = (unsigned char*) fmalloc(plainBlockSize * numBlocks);
ptextPtr = ptextResult;
ptextLenTotal = 0;
while(ctextLen) {
if(ctextLen == cipherBlockSize) {
finalBlock = 1;
}
else {
finalBlock = 0;
}
frtn = feeFEEDDecryptBlock(feed,
ctext,
cipherBlockSize,
ptext,
&ptextLen,
finalBlock);
if(frtn) {
dbgLog(("feeFEEDDecryptBlock: %s\n",
feeReturnString(frtn)));
break;
}
if(ptextLen) {
if(ptextLen > plainBlockSize) {
dbgLog(("feeFEEDDecrypt: ptext overflow!\n"));
frtn = FR_Internal;
break;
}
bcopy(ptext, ptextPtr, ptextLen);
ptextPtr += ptextLen;
ptextLenTotal += ptextLen;
}
ctext += cipherBlockSize;
ctextLen -= cipherBlockSize;
}
ffree(ptext);
if(frtn) {
ffree(ptextResult);
*plainText = NULL;
*plainTextLen = 0;
}
else {
*plainText = ptextResult;
*plainTextLen = ptextLenTotal;
}
return frtn;
}
#endif