+++ /dev/null
-/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved.
- *
- * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
- * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
- * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
- * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
- * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
- * EXPOSE YOU TO LIABILITY.
- ***************************************************************************
- *
- * FeeFEED.c - generic, portable FEED encryption object, expanionless version
- *
- * Revision History
- * ----------------
- * 10/06/98 ap
- * Changed to compile with C++.
- * 20 Jan 1998 at Apple
- * Mods for primeType == PT_GENERAL case.
- * 12 Jun 1997 at Apple
- * Was curveOrderJustify(), is lesserX1OrderJustify()
- * 31 Mar 1997 at Apple
- * Fixed initialRS leak
- * 3 Mar 1997 at Apple
- * Trimmed plainBlockSize by one byte if q mod 8 = 0
- * 30 Jan 1997 at NeXT
- * Created.
- */
-
-/*
- * FIXME - a reusable init function would be nice (i.e., free up
- * session-dependent state and re-init it)...
- */
-#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
-
-/*
- * Minimum combined size of random r and s, in bytes. For small q sizes,
- * r and s may be even smaller, but we never truncate them to smaller than
- * this.
- * This must be kept in sync with constant of same name in FEED.java.
- */
-#define RS_MIN_SIZE 16
-
-/*
- * Private data.
- */
-typedef struct {
- curveParams *cp;
-
- /*
- * the clues are initially (r * ourPriv * theirPub(+/-)).
- */
- giant cluePlus;
- giant clueMinus;
-
- /*
- * sPlus and sMinus are based on the random s generated at encrypt
- * time. Values are s * x1{Plus,Minus}.
- */
- giant sPlus;
- giant sMinus;
- giant r; /* random, generated at encrypt time */
- unsigned plainBlockSize; /* plaintext block size */
- unsigned cipherBlockSize; /* ciphertext block size */
- unsigned char *initialRS; /* initial random R,S as bytes */
- unsigned initialRSSize; /* in bytes */
- feeFEEDExp feedExp; /* for encr/decr r+s params */
-
- /*
- * The first few blocks of ciphertext in a stream are the 2:1-FEED
- * encrypted r and s parameters. While decrypting, we stash incoming
- * ciphertext in rsCtext until we get enough ciphertext to decrypt
- * initialRS. RsBlockCount keeps a running count of the
- * cipherBlocks received. When rsBlockCount == rsSizeCipherBlocks, we
- * FEEDExp-decrypt rsCtext to get r and s (actually, to get
- * initialRS; r and s are extraced later in initFromRS()).
- *
- * During encrypt, if rsBlockCount is zero, the first thing we send as
- * ciphertext is the FEED-encrypted initialRS.
- */
- unsigned char *rsCtext; /* buffer for encrypted initialRS */
- unsigned rsBlockCount; /* running total of incoming rs
- * cipherblocks */
-
- int forEncrypt; /* added for feeFEED*TextSize() */
-
- /*
- * These are calculated at init time - for encrypt and
- * decrypt - as an optimization.
- */
- unsigned rsCtextSize; /* number of meaningful bytes in
- * rsCtext */
- unsigned rsSizeCipherBlocks; /* # of our cipherblocks holding
- * rsCtext */
-
- /*
- * temporary variables used for encrypt/decrypt. The values in these
- * are not needed to be kept from block to block; we just
- * alloc them once per lifetime of a feeFEED object as an optimization.
- */
- giant xp; /* plaintext */
- giant xm; /* ciphertext */
- giant tmp1; /* scratch */
- giant tmp2; /* scratch */
-} feedInst;
-
-/*
- * "zero residue" indicator.
- */
-#define RESID_ZERO 0xff
-
-/*
- * cons up:
- * cluePlus(0)
- * clueMinus(0)
- * sPlus
- * sMinus
- * r
- * Assumes:
- * cluePlus = clueMinus = ourPriv * theirPub
- * initialRS
- * initialRSSize
- * cp
- *
- * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting
- * first block of data.
- */
-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 // FEED_DEBUG
-
- 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 // FEE_DEBUG
- /*
- * Justify r and s to be in [2, minimumX1Order].
- */
- lesserX1OrderJustify(finst->r, finst->cp);
- lesserX1OrderJustify(s, finst->cp);
-
- /*
- * sPlus = s * x1Plus
- * sMinus = s * x1Minus
- */
- 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);
-
- /*
- * And finally, the initial clues. They are currently set to
- * ourPriv * theirPub.
- */
- #if FEED_DEBUG
- printf("cluePlus : "); printGiant(finst->cluePlus);
- printf("clueMinus: "); printGiant(finst->clueMinus);
- #endif // FEED_EEBUG
-
- 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 // FEED_DEBUG
-
- freeGiant(s);
- return FR_Success;
-}
-
-/*
- * Alloc and init a feeFEED object associated with specified public and
- * private keys.
- */
-feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey,
- feePubKey theirPubKey,
- int forEncrypt, // 0 ==> decrypt 1 ==> encrypt
- feeRandFcn randFcn, // optional
- 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);
- }
-
- /*
- * cluePlus = ourPriv * theirPub+
- * clueMinus = ourPriv * theirPub-
- */
- 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); // cluePlus = theirPub+
- elliptic_simple(finst->cluePlus, privGiant, finst->cp);
- k = feePubKeyMinusCurve(theirPubKey);
- gtog(k->x, finst->clueMinus); // theirPub-
- elliptic_simple(finst->clueMinus, privGiant, finst->cp);
-
- /*
- * Set up block sizes.
- */
- if(finst->cp->primeType == FPT_General) {
- unsigned blen = bitlen(finst->cp->basePrime);
-
- finst->plainBlockSize = blen / 8;
- if((blen & 0x7) == 0) {
- /*
- * round down some more...
- */
- finst->plainBlockSize--;
- }
- }
- else {
- finst->plainBlockSize = finst->cp->q / 8;
- if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
- /*
- * Special case, with q mod 8 == 0. Here we have to
- * trim back the plainBlockSize by one byte.
- */
- finst->plainBlockSize--;
- }
- }
- finst->cipherBlockSize = finst->cp->minBytes + 1;
-
- /*
- * the size of initialRS is subject to tweaking - if we make it
- * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock
- * in our ciphertext.
- */
- finst->initialRSSize = finst->plainBlockSize * 2;
- if(finst->initialRSSize > RS_MIN_SIZE) {
- unsigned minPlainBlocks;
- unsigned maxSize;
-
- /*
- * How many plainblocks to hold RS_MIN_SIZE?
- */
- minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) /
- finst->plainBlockSize;
-
- /*
- * Max size = that many plainblocks, less 2 bytes (to avoid
- * extra residue block).
- */
- maxSize = minPlainBlocks * finst->plainBlockSize - 2;
-
- /*
- * But don't bother with more than 2 plainblocks worth
- */
- if(finst->initialRSSize > maxSize) {
- finst->initialRSSize = maxSize;
- }
- }
- /* else leave it alone, that's small enough */
-
- if(forEncrypt) {
- feeRand frand = NULL;
-
- /*
- * Encrypt-capable FEEDExp object
- */
- finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey,
- randFcn,
- randRef);
- if(finst->feedExp == NULL) {
- goto abort;
- }
-
- /*
- * Generate initial r and s data.
- */
- 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 {
- /*
- * Decrypt-capable FEEDExp object
- */
- finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey,
- randFcn,
- randRef);
- if(finst->feedExp == NULL) {
- goto abort;
- }
-
- }
-
- /*
- * Figure out how many of our cipherblocks it takes to hold
- * a FEEDExp-encrypted initialRS. If initialRSSize is an exact
- * multiple of expPlainSize, we get an additional feedExp
- * residue block.
- */
- expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp);
- expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp);
- expBlocks = (finst->initialRSSize + expPlainSize - 1) /
- expPlainSize;
- if((finst->initialRSSize % expPlainSize) == 0) {
- expBlocks++;
- }
-
- /*
- * Total meaningful bytes of encrypted initialRS
- */
- finst->rsCtextSize = expBlocks * expCipherSize;
-
- /*
- * Number of our cipherblocks it takes to hold rsCtextSize
- */
- finst->rsSizeCipherBlocks = (finst->rsCtextSize +
- finst->cipherBlockSize - 1) / finst->cipherBlockSize;
- if(!forEncrypt) {
- finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks *
- finst->cipherBlockSize);
- }
-
- /*
- * Sanity check...
- */
- #if FEED_DEBUG
- {
- unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp);
-
- /*
- * FEEDExp has one more giant in ciphertext, plaintext is
- * same size
- */
- 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 // FEED_DEBUG
-
- 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;
-}
-
-/*
- * Calculate size of buffer currently needed to encrypt one block of
- * plaintext. Also used to calculate required input during decrypt
- * to get any output.
- */
-unsigned feeFEEDCipherBufSize(feeFEED feed,
- int finalBlock)
-{
- feedInst *finst = (feedInst *) feed;
- unsigned blocks = 1; // always at least one block of ciphertext
-
- if(finst->rsBlockCount == 0) {
- /* haven't sent/seen encrypted RS yet */
- blocks += finst->rsSizeCipherBlocks;
- }
-
- if(finalBlock) {
- /* only needed if ptext is aligned, but tell caller to malloc */
- blocks++;
- }
- bprintf(("$$$ feeFEEDCipherBufSize( %s, %s): rtn 0x%x\n",
- finst->forEncrypt ? "encrypt" : "decrypt",
- finalBlock ? " final" : "!final",
- blocks * finst->cipherBlockSize));
- return blocks * finst->cipherBlockSize;
-}
-
-/*
- * Return the size of ciphertext currently needed to encrypt specified
- * size of plaintext. Also can be used to calculate size of ciphertext
- * which can be decrypted into specified size of plaintext.
- */
-unsigned feeFEEDCipherTextSize(feeFEED feed,
- unsigned plainTextSize,
- int finalBlock)
-{
- feedInst *finst = (feedInst *) feed;
-
- /* how many blocks of plaintext? */
- unsigned blocks = (plainTextSize + finst->plainBlockSize - 1) /
- finst->plainBlockSize;
-
- if(finst->forEncrypt) {
- /* have we generated RS? */
- if(finst->rsBlockCount == 0) {
- /* haven't sent encrypted RS yet */
- blocks += finst->rsSizeCipherBlocks;
- }
-
- /* final? residue? */
- if(finalBlock) {
- if((plainTextSize % finst->plainBlockSize) == 0) {
- blocks++;
- }
- }
- } /* encrypting */
- else {
- /*
- * Decrypting - how much ciphertext can we decrypt safely into
- * specified plaintext? Add in RS if we haven't seen it all
- * yet.
- */
- #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;
-}
-
-/*
- * Return the size of plaintext currently needed to decrypt specified size
- * of ciphertext. Also can be used to calculate size of plaintext
- * which can be encrypted into specified size of ciphertext.
- */
-unsigned feeFEEDPlainTextSize(feeFEED feed,
- unsigned cipherTextSize,
- int finalBlock) // ignored if !forEncrypt
-{
- feedInst *finst = (feedInst *) feed;
-
- /* start with basic cipher block count */
- unsigned cipherBlocks = (cipherTextSize + finst->cipherBlockSize - 1) /
- finst->cipherBlockSize;
-
- /* where are we in the RS stream? */
- unsigned rsBlocksToGo = finst->rsSizeCipherBlocks - finst->rsBlockCount;
- if(finst->forEncrypt) {
- /*
- * Encrypting, seeking plaintext size we can encrypt given
- * a specified size of ciphertext.
- */
- if(rsBlocksToGo >= cipherBlocks) {
- /* no room! next encrypt would overflow ctext buffer! */
- return 0;
- }
- cipherBlocks -= rsBlocksToGo;
-
- /* another constraint - residue */
- if(finalBlock) {
- if(cipherBlocks) {
- /* skip if already zero... */
- cipherBlocks--;
- }
- }
- } /* encrypting */
- else {
- /* decrypting */
- if(rsBlocksToGo >= cipherBlocks) {
- /* still processing RS, no plaintext will be generated. Play it real
- * safe and just tell caller one block. */
- cipherBlocks = 1;
- }
- else {
- /* diminish by size of RS to be gobbled with no output */
- 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;
-}
-
-/*
- * Bits in last byte of cipherblock
- */
-#define CLUE_BIT 0x01 /* 1 ==> plus curve */
-#define CLUE_PLUS 0x01
-#define CLUE_MINUS 0x00
-#define PARITY_BIT 0x02 /* 1 ==> plus 's' arg to elliptic_add() */
-#define PARITY_PLUS 0x02
-#define PARITY_MINUS 0x00
-
-/*
- * 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;
-}
-
-/*
- * 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;
-}
-
-/*
- * Convenience routines to encrypt & decrypt multi-block data.
- */
-feeReturn feeFEEDEncrypt(feeFEED feed,
- const unsigned char *plainText,
- unsigned plainTextLen,
- unsigned char **cipherText, // malloc'd and RETURNED
- unsigned *cipherTextLen) // RETURNED
-{
- const unsigned char *ptext; // per block
- unsigned ptextLen; // total to go
- unsigned thisPtextLen; // per block
- unsigned char *ctext; // per block
- unsigned ctextLen; // per block
- unsigned char *ctextResult; // to return
- unsigned ctextResultLen; // size of ctextResult
- unsigned char *ctextPtr;
- unsigned ctextLenTotal; // running total
- 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;
-
- /*
- * Calculate the worst-case size needed to hold all of the ciphertext
- */
- 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 // FEE_DEBUG
- }
- return frtn;
-
-}
-
-feeReturn feeFEEDDecrypt(feeFEED feed,
- const unsigned char *cipherText,
- unsigned cipherTextLen,
- unsigned char **plainText, // malloc'd and RETURNED
- unsigned *plainTextLen) // RETURNED
-{
- const unsigned char *ctext;
- unsigned ctextLen; // total to go
- unsigned char *ptext; // per block
- unsigned ptextLen; // per block
- unsigned char *ptextResult; // to return
- unsigned char *ptextPtr;
- unsigned ptextLenTotal; // running total
- 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;
- }
- /*
- * note ptextLen == 0 is normal termination case for
- * plainTextLen % plainBlockSize == 0.
- * Also expected for first 4 blocks of ciphertext;
- * proceed (we break when ctextLen is exhausted).
- */
- ctext += cipherBlockSize;
- ctextLen -= cipherBlockSize;
- }
-
- ffree(ptext);
- if(frtn) {
- ffree(ptextResult);
- *plainText = NULL;
- *plainTextLen = 0;
- }
- else {
- *plainText = ptextResult;
- *plainTextLen = ptextLenTotal;
- }
- return frtn;
-
-}
-
-#endif /* CRYPTKIT_ASYMMETRIC_ENABLE */