#include "ckconfig.h"
#include "feeTypes.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 "feeDebug.h"
#include <stdlib.h>
#define FEED_DEBUG 0
#define PRINT_GIANT(g) printGiant(g)
#define CLUE_ELL_ADD_SIGN 0x01
#define CLUE_ELL_ADD_SIGN_PLUS 0x01
#define CLUE_ELL_ADD_SIGN_MINUS 0x00
typedef struct {
key plus;
key minus;
unsigned plainBlockSize;
unsigned cipherBlockSize;
curveParams *cp;
giant gPriv;
feeRand rand;
feeRandFcn randFcn;
void *randRef;
giant xp;
giant xc;
giant xq;
giant xm;
giant xaux;
unsigned char *randData;
} feedInst;
#define RESID_ZERO 0xff
feeFEEDExp feeFEEDExpNewWithPubKey(
feePubKey pubKey,
feeRandFcn randFcn, void *randRef)
{
feedInst *finst = (feedInst *) fmalloc(sizeof(feedInst));
giant privGiant;
finst->cp = curveParamsCopy(feePubKeyCurveParams(pubKey));
finst->plus = new_public_with_key(feePubKeyPlusCurve(pubKey),
finst->cp);
finst->minus = new_public_with_key(feePubKeyMinusCurve(pubKey),
finst->cp);
privGiant = feePubKeyPrivData(pubKey);
if(privGiant) {
finst->gPriv = newGiant(finst->cp->maxDigits);
gtog(privGiant, finst->gPriv);
}
else {
finst->gPriv = NULL;
}
if(finst->cp->primeType == FPT_General) {
unsigned blen = bitlen(finst->cp->basePrime);
finst->plainBlockSize = blen / 8;
if((blen % 8) == 0) {
finst->plainBlockSize--;
}
}
else {
finst->plainBlockSize = finst->cp->q / 8;
if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
finst->plainBlockSize--;
}
}
finst->cipherBlockSize = (2 * finst->cp->minBytes) + 1;
finst->xp = newGiant(finst->cp->maxDigits);
finst->xc = newGiant(finst->cp->maxDigits);
finst->xq = newGiant(finst->cp->maxDigits);
finst->xm = newGiant(finst->cp->maxDigits);
finst->xaux = newGiant(finst->cp->maxDigits);
finst->rand = NULL;
finst->randData = NULL;
finst->randFcn = randFcn;
finst->randRef = randRef;
return finst;
}
void feeFEEDExpFree(feeFEEDExp feed)
{
feedInst *finst = (feedInst *) feed;
free_key(finst->plus);
free_key(finst->minus);
freeGiant(finst->xc);
clearGiant(finst->xp); freeGiant(finst->xp);
clearGiant(finst->xq); freeGiant(finst->xq);
freeGiant(finst->xm);
clearGiant(finst->xaux); freeGiant(finst->xaux);
if(finst->gPriv) {
clearGiant(finst->gPriv);
freeGiant(finst->gPriv);
}
if(finst->rand) {
feeRandFree(finst->rand);
}
if(finst->randData) {
ffree(finst->randData);
}
if(finst->cp) {
freeCurveParams(finst->cp);
}
ffree(finst);
}
unsigned feeFEEDExpPlainBlockSize(feeFEEDExp feed)
{
feedInst *finst = (feedInst *) feed;
return finst->plainBlockSize;
}
unsigned feeFEEDExpCipherBlockSize(feeFEEDExp feed)
{
feedInst *finst = (feedInst *) feed;
return finst->cipherBlockSize;
}
unsigned feeFEEDExpCipherBufSize(feeFEEDExp feed)
{
feedInst *finst = (feedInst *) feed;
return 2 * finst->cipherBlockSize;
}
unsigned feeFEEDExpCipherTextSize(feeFEEDExp feed, unsigned plainTextSize)
{
feedInst *finst = (feedInst *) feed;
unsigned blocks = (plainTextSize + finst->plainBlockSize - 1) /
finst->plainBlockSize;
if((plainTextSize % finst->plainBlockSize) == 0) {
blocks++;
}
return blocks * finst->cipherBlockSize;
}
unsigned feeFEEDExpPlainTextSize(feeFEEDExp feed, unsigned cipherTextSize)
{
feedInst *finst = (feedInst *) feed;
unsigned blocks = (cipherTextSize + finst->cipherBlockSize - 1) /
finst->cipherBlockSize;
return blocks * finst->plainBlockSize;
}
feeReturn feeFEEDExpEncryptBlock(feeFEEDExp feed,
const unsigned char *plainText,
unsigned plainTextLen,
unsigned char *cipherText,
unsigned *cipherTextLen, int finalBlock)
{
feedInst *finst = (feedInst *) feed;
int index;
char g = 0;
key B;
unsigned char *ptext;
unsigned ctextLen;
feeReturn frtn = FR_Success;
giant x1;
unsigned randLen;
curveParams *cp = finst->cp;
randLen = cp->minBytes+8;
if(plainTextLen > finst->plainBlockSize) {
return FR_IllegalArg;
}
else if ((plainTextLen < finst->plainBlockSize) && !finalBlock) {
return FR_IllegalArg;
}
if((finst->randFcn == NULL) && (finst->rand == NULL)) {
finst->rand = feeRandAlloc();
}
if(finst->randData == NULL) {
finst->randData = (unsigned char*) fmalloc(randLen);
}
if(finalBlock) {
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;
}
else {
ptext[finst->plainBlockSize - 1] = plainTextLen;
}
#if FEED_DEBUG
printf("encrypt: resid 0x%x\n", ptext[finst->plainBlockSize - 1]);
#endif
}
deserializeGiant(ptext, finst->xp, finst->plainBlockSize);
ffree(ptext);
}
else {
deserializeGiant(plainText, finst->xp, plainTextLen);
}
#if FEED_DEBUG
printf("encrypt:\n");
printf(" xp : "); PRINT_GIANT(finst->xp);
#endif
index = which_curve(finst->xp, finst->cp);
if(index == CURVE_PLUS) {
B = finst->plus;
x1 = finst->cp->x1Plus;
}
else {
B = finst->minus;
x1 = finst->cp->x1Minus;
}
#if FEED_DEBUG
printf(" which_curve: %s\n",
(index == CURVE_PLUS) ? "CURVE_PLUS" : "CURVE_MINUS");
#endif
if(finst->randFcn != NULL) {
finst->randFcn(finst->randRef, finst->randData, randLen);
}
else {
feeRandBytes(finst->rand, finst->randData, randLen);
}
deserializeGiant(finst->randData, finst->xaux, randLen);
#if FEE_DEBUG
if(isZero(finst->xaux)) {
printf("feeFEEDExpEncryptBlock: random xaux = 0!\n");
}
#endif
lesserX1OrderJustify(finst->xaux, cp);
#if FEED_DEBUG
printf(" xaux: "); PRINT_GIANT(finst->xaux);
#endif
gtog(B->x, finst->xq); elliptic_simple(finst->xq, finst->xaux, cp);
#if FEED_DEBUG
printf(" r(pubB?): "); PRINT_GIANT(finst->xq);
#endif
elliptic_add(finst->xp, finst->xq, finst->xm, cp, SIGN_PLUS);
gtog(x1, finst->xc);
elliptic_simple(finst->xc, finst->xaux, cp);
elliptic_add(finst->xm, finst->xq, finst->xaux, cp, SIGN_PLUS);
if(gcompg(finst->xaux, finst->xp) == 0) {
g |= CLUE_ELL_ADD_SIGN_PLUS;
}
else {
g |= CLUE_ELL_ADD_SIGN_MINUS;
#if FEED_DEBUG
elliptic_add(finst->xm, finst->xq, finst->xaux, cp, SIGN_MINUS);
if(gcompg(finst->xaux, finst->xp)) {
printf("*******elliptic_add(xm, xq, -1) != xp! *************\n");
printf(" xq : "); PRINT_GIANT(finst->xq);
printf(" ell_add(xm, xq, -1) : "); PRINT_GIANT(finst->xaux);
}
#endif
}
serializeGiant(finst->xm, cipherText, cp->minBytes);
cipherText += cp->minBytes;
serializeGiant(finst->xc, cipherText, cp->minBytes);
cipherText += cp->minBytes;
*cipherText++ = g;
ctextLen = finst->cipherBlockSize;
#if FEED_DEBUG
printf(" xm : "); PRINT_GIANT(finst->xm);
printf(" xc : "); PRINT_GIANT(finst->xc);
printf(" g : %d\n", g);
#endif if(finalBlock && (plainTextLen == finst->plainBlockSize)) {
unsigned moreCipher;
#if FEED_DEBUG
printf("encrypt: one more empty block\n");
#endif
frtn = feeFEEDExpEncryptBlock(feed,
NULL, 0, cipherText, &moreCipher,
1);
if(frtn == FR_Success) {
ctextLen += moreCipher;
}
}
*cipherTextLen = ctextLen;
return frtn;
}
feeReturn feeFEEDExpDecryptBlock(feeFEEDExp feed,
const unsigned char *cipherText,
unsigned cipherTextLen,
unsigned char *plainText,
unsigned *plainTextLen, int finalBlock)
{
feedInst *finst = (feedInst *) feed;
char g;
int s;
feeReturn frtn = FR_Success;
curveParams *cp = finst->cp;
if(finst->gPriv == NULL) {
return FR_BadPubKey;
}
deserializeGiant(cipherText, finst->xm, finst->cp->minBytes);
cipherText += finst->cp->minBytes;
deserializeGiant(cipherText, finst->xc, finst->cp->minBytes);
cipherText += finst->cp->minBytes;
g = *cipherText;
#if FEED_DEBUG
printf("decrypt g=%d\n", g);
printf(" privKey : "); PRINT_GIANT(finst->gPriv);
printf(" xm : "); PRINT_GIANT(finst->xm);
printf(" xc : "); PRINT_GIANT(finst->xc);
#endif
if((g & CLUE_ELL_ADD_SIGN) == CLUE_ELL_ADD_SIGN_PLUS) {
s = SIGN_PLUS;
}
else {
s = SIGN_MINUS;
}
elliptic_simple(finst->xc, finst->gPriv, cp);
#if FEED_DEBUG
printf(" xc1 : "); PRINT_GIANT(finst->xc);
#endif
elliptic_add(finst->xm, finst->xc, finst->xp, cp, s);
#if FEED_DEBUG
printf(" xp : "); PRINT_GIANT(finst->xp);
#endif
if(finalBlock) {
unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize);
serializeGiant(finst->xp, ptext, finst->plainBlockSize);
*plainTextLen = ptext[finst->plainBlockSize - 1];
#if FEED_DEBUG
printf("decrypt: resid 0x%x\n", *plainTextLen);
#endif
if(*plainTextLen == RESID_ZERO) {
*plainTextLen = 0;
}
else if(*plainTextLen > (finst->plainBlockSize - 1)) {
dbgLog(("feeFEEDExpDecryptBlock: ptext overflow!\n"));
frtn = FR_BadCipherText;
}
else {
bcopy(ptext, plainText, *plainTextLen);
}
ffree(ptext);
}
else {
*plainTextLen = finst->plainBlockSize;
serializeGiant(finst->xp, plainText, *plainTextLen);
}
return frtn;
}
feeReturn feeFEEDExpEncrypt(feeFEEDExp 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(plainTextLen == 0) {
dbgLog(("feeFEEDExpDecrypt: NULL plainText\n"));
return FR_IllegalArg;
}
ptext = plainText;
ptextLen = plainTextLen;
ctext = (unsigned char*) fmalloc(feeFEEDExpCipherBufSize(feed));
plainBlockSize = feeFEEDExpPlainBlockSize(feed);
numBlocks = (plainTextLen + plainBlockSize - 1)/plainBlockSize;
ctextResultLen = (numBlocks + 1) * feeFEEDExpCipherBlockSize(feed);
ctextResult = (unsigned char*) fmalloc(ctextResultLen);
ctextPtr = ctextResult;
ctextLenTotal = 0;
while(1) {
if(ptextLen <= plainBlockSize) {
finalBlock = 1;
thisPtextLen = ptextLen;
}
else {
finalBlock = 0;
thisPtextLen = plainBlockSize;
}
frtn = feeFEEDExpEncryptBlock(feed,
ptext,
thisPtextLen,
ctext,
&ctextLen,
finalBlock);
if(frtn) {
dbgLog(("feeFEEDExpEncrypt: encrypt error: %s\n",
feeReturnString(frtn)));
break;
}
if(ctextLen == 0) {
dbgLog(("feeFEEDExpEncrypt: null ciphertext\n"));
frtn = FR_Internal;
break;
}
bcopy(ctext, ctextPtr, ctextLen);
ctextLenTotal += ctextLen;
if(ctextLenTotal > ctextResultLen) {
dbgLog(("feeFEEDExpEncrypt: 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(feeFEEDExpCipherTextSize(feed, plainTextLen) !=
ctextLenTotal) {
printf("feeFEEDExpEncrypt: feeFEEDCipherTextSize "
"error!\n");
printf("ptext %d exp ctext %d actual ctext %d\n",
plainTextLen,
feeFEEDExpCipherTextSize(feed, plainTextLen),
ctextLenTotal);
}
#endif }
return frtn;
}
feeReturn feeFEEDExpDecrypt(feeFEEDExp 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 =
feeFEEDExpPlainBlockSize(feed);
unsigned cipherBlockSize =
feeFEEDExpCipherBlockSize(feed);
if(cipherTextLen % cipherBlockSize) {
dbgLog(("feeFEEDExpDecrypt: unaligned cipherText\n"));
return FR_BadCipherText;
}
if(cipherTextLen == 0) {
dbgLog(("feeFEEDExpDecrypt: 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 = feeFEEDExpDecryptBlock(feed,
ctext,
cipherBlockSize,
ptext,
&ptextLen,
finalBlock);
if(frtn) {
dbgLog(("feeFEEDExpDecryptBlock: %s\n",
feeReturnString(frtn)));
break;
}
if(ptextLen == 0) {
if(!finalBlock) {
dbgLog(("feeFEEDExpDecrypt: decrypt sync"
" error!\n"));
frtn = FR_BadCipherText;
}
break;
}
else if(ptextLen > plainBlockSize) {
dbgLog(("feeFEEDExpDecrypt: ptext overflow!\n"));
frtn = FR_Internal;
break;
}
else {
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;
}