/* * Encrypt a block or less of data. Caller malloc's cipherText. * Generates up to feeFEEDCipherBufSize() bytes of ciphertext. */ feeReturn feeFEEDEncryptBlock(feeFEED feed, const unsigned char *plainText, unsigned plainTextLen, unsigned char *cipherText, unsigned *cipherTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; unsigned ctextLen = 0; feeReturn frtn = FR_Success; int whichCurve; giant thisClue; // not alloc'd or freed giant thisS; // ditto unsigned char clueByte; if(plainTextLen > finst->plainBlockSize) { return FR_IllegalArg; } if((plainTextLen < finst->plainBlockSize) && !finalBlock) { return FR_IllegalArg; } if(finst->initialRS == NULL) { /* * Init'd for decrypt? */ return FR_IllegalArg; } /* * First block - encrypt initialRS via FEEDExp */ if(finst->rsBlockCount == 0) { unsigned char *thisCtext; // malloc's by FEEDExp unsigned padLen; if(finst->initialRS == NULL) { /* * init'd for decrypt or reused */ dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n")); return FR_IllegalArg; } frtn = feeFEEDExpEncrypt(finst->feedExp, finst->initialRS, finst->initialRSSize, &thisCtext, &ctextLen); if(frtn) { /* * Should never happen... */ 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); // zeros to write #if 0 /* FEED_DEBUG */ /* * Hard-coded assumptions and tests about initRSSize... * Currently we assume that initRSSize % expBlockSize = 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 // FEED_DEBUG /* * pad to multiple of (our) cipherblock size. */ while(padLen) { *cipherText++ = 0; ctextLen++; padLen--; } } /* * plaintext to giant xp */ if(finalBlock) { unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); bzero(ptext, finst->plainBlockSize); if(plainTextLen) { /* * skip for empty block with resid length 0 */ bcopy(plainText, ptext, plainTextLen); } if(plainTextLen < finst->plainBlockSize) { if(plainTextLen == 0) { /* * Special case - resid block with no actual plaintext. * Can't actually write zero here; it screws up * deserializing the giant during decrypt */ 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)); } } /* * else handle evenly aligned case (i.e., finalBlock true * and (plainTextLen == plainBlockSize)) below... */ deserializeGiant(ptext, finst->xp, finst->plainBlockSize); ffree(ptext); } else { deserializeGiant(plainText, finst->xp, plainTextLen); } /* * encrypt xp * xm = xp + clue(+/-) * determine parity needed to restore xp * parity = ((xm + clue(+/-) == xp) ? 1 : -1 * and adjust clue * clue[n+1] = r * clue[n] + (s * P1) */ 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; } // calculate xm elliptic_add(thisClue, finst->xp, finst->xm, finst->cp, SIGN_PLUS); // save xm + clue in tmp1 elliptic_add(finst->xm, thisClue, finst->tmp1, finst->cp, SIGN_PLUS); // Adjust clue elliptic_simple(thisClue, finst->r, finst->cp); gtog(thisClue, finst->tmp2); elliptic_add(finst->tmp2, thisS, thisClue, finst->cp, SIGN_PLUS); /* * Calculate parity */ if(gcompg(finst->tmp1, finst->xp) == 0) { clueByte |= PARITY_PLUS; } /* * Ciphertext = (xm, clueByte) */ 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 // FEED_DEBUG if(finalBlock && (plainTextLen == finst->plainBlockSize)) { /* * Special case: finalBlock true, plainTextLen == blockSize. * In this case we generate one more block of ciphertext, * with a resid length of zero. */ unsigned moreCipher; // additional cipherLen frtn = feeFEEDEncryptBlock(feed, NULL, // plainText not used 0, // resid cipherText, // append... &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 createFEEDExp(feePubKey sendPrivKey, // for sig only 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; feeFEEDExp feed = NULL; unsigned char *cipherText = NULL; unsigned cipherTextLen; unsigned char *sigData = NULL; unsigned sigDataLen = 0; feeCipherFile cfile = NULL; unsigned char *pubKeyString = NULL; // of sendPrivKey, for sig unsigned pubKeyStringLen = 0; if(recvPubKey == NULL) { return FR_BadPubKey; } /* * FEEDExp encrypt plaintext */ feed = feeFEEDExpNewWithPubKey(recvPubKey, NULL, NULL); if(feed == NULL) { frtn = FR_BadPubKey; goto out; } frtn = feeFEEDExpEncrypt(feed, plainText, plainTextLen, &cipherText, &cipherTextLen); if(frtn) { goto out; } if(genSig) { if(sendPrivKey == NULL) { frtn = FR_IllegalArg; goto out; } /* * We generate signature on ciphertext by convention. */ frtn = feePubKeyCreateSignature(sendPrivKey, cipherText, cipherTextLen, &sigData, &sigDataLen); if(frtn) { goto out; } /* * Sender's public key string */ frtn = feePubKeyCreateKeyString(sendPrivKey, (char **)&pubKeyString, &pubKeyStringLen); if(frtn) { /* * Huh? */ frtn = FR_BadPubKey; goto out; } } /* * Cons up a cipherfile */ cfile = feeCFileNewFromCipherText(CFE_FEEDExp, 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) { feeFEEDExpFree(feed); } if(sigData) { ffree(sigData); } if(pubKeyString) { ffree(pubKeyString); } *cipherFile = cfile; return frtn; }