/ OSX / libsecurity_cryptkit / lib / feeFEED.c
feeFEED.c
   1  /* Copyright (c) 1998,2011,2014 Apple Inc.  All Rights Reserved.
   2   *
   3   * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
   4   * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
   5   * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE
   6   * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
   7   * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
   8   * EXPOSE YOU TO LIABILITY.
   9   ***************************************************************************
  10   *
  11   * FeeFEED.c - generic, portable FEED encryption object, expanionless version
  12   *
  13   * Revision History
  14   * ----------------
  15   * 10/06/98		ap
  16   *	Changed to compile with C++.
  17   * 20 Jan 1998 at Apple
  18   * 	Mods for primeType == PT_GENERAL case.
  19   * 12 Jun 1997 at Apple
  20   *	Was curveOrderJustify(), is lesserX1OrderJustify()
  21   * 31 Mar 1997 at Apple
  22   *	Fixed initialRS leak
  23   *  3 Mar 1997 at Apple
  24   *	Trimmed plainBlockSize by one byte if q mod 8 = 0
  25   * 30 Jan 1997 at NeXT
  26   *	Created.
  27   */
  28  
  29  /*
  30   * FIXME - a reusable init function would be nice (i.e., free up
  31   * session-dependent state and re-init it)...
  32   */
  33  #include "ckconfig.h"
  34  
  35  #include "feeTypes.h"
  36  #include "feeFEED.h"
  37  #include "feeFEEDExp.h"
  38  #include "feePublicKey.h"
  39  #include "feePublicKeyPrivate.h"
  40  #include "elliptic.h"
  41  #include "falloc.h"
  42  #include "feeRandom.h"
  43  #include "ckutilities.h"
  44  #include "feeFunctions.h"
  45  #include "platform.h"
  46  #include "curveParams.h"
  47  #include "feeDebug.h"
  48  #include <stdlib.h>
  49  #include <stdio.h>
  50  
  51  #define FEED_DEBUG	0
  52  #define BUFFER_DEBUG	0
  53  #if		BUFFER_DEBUG
  54  #define bprintf(s)	printf s
  55  #else
  56  #define bprintf(s)
  57  #endif
  58  
  59  /*
  60   * Minimum combined size of random r and s, in bytes. For small q sizes,
  61   * r and s may be even smaller, but we never truncate them to smaller than
  62   * this.
  63   * This must be kept in sync with constant of same name in FEED.java.
  64   */
  65  #define RS_MIN_SIZE	16
  66  
  67  /*
  68   * Private data.
  69   */
  70  typedef struct {
  71  	curveParams		*cp;
  72  
  73  	/*
  74  	 * the clues are initially (r * ourPriv * theirPub(+/-)).
  75  	 */
  76  	giant			cluePlus;
  77  	giant			clueMinus;
  78  
  79  	/*
  80  	 * sPlus and sMinus are based on the random s generated at encrypt
  81  	 * time. Values are s * x1{Plus,Minus}.
  82  	 */
  83  	giant			sPlus;
  84  	giant			sMinus;
  85  	giant			r;					/* random, generated at encrypt time */
  86  	unsigned		plainBlockSize;		/* plaintext block size */
  87  	unsigned		cipherBlockSize;	/* ciphertext block size */
  88  	unsigned char 	*initialRS;			/* initial random R,S as bytes */
  89  	unsigned		initialRSSize;		/* in bytes */
  90  	feeFEEDExp		feedExp;			/* for encr/decr r+s params */
  91  
  92  	/*
  93  	 * The first few blocks of ciphertext in a stream are the 2:1-FEED
  94  	 * encrypted r and s parameters. While decrypting, we stash incoming
  95  	 * ciphertext in rsCtext until we get enough ciphertext to decrypt
  96  	 * initialRS. RsBlockCount keeps a running count of the
  97  	 * cipherBlocks received. When rsBlockCount == rsSizeCipherBlocks, we
  98  	 * FEEDExp-decrypt rsCtext to get r and s (actually, to get
  99  	 * initialRS; r and s are extraced later in initFromRS()).
 100  	 *
 101  	 * During encrypt, if rsBlockCount is zero, the first thing we send as
 102  	 * ciphertext is the FEED-encrypted initialRS.
 103  	 */
 104  	unsigned char	*rsCtext;			/* buffer for encrypted initialRS */
 105  	unsigned		rsBlockCount;		/* running total of incoming rs
 106  										 *   cipherblocks */
 107  
 108  	int 			forEncrypt;			/* added for feeFEED*TextSize() */
 109  	
 110  	/*
 111   	 * These are calculated at init time - for encrypt and
 112  	 * decrypt - as an optimization.
 113  	 */
 114  	unsigned 		rsCtextSize;		/* number of meaningful bytes in
 115  										 *   rsCtext */
 116  	unsigned		rsSizeCipherBlocks;	/* # of our cipherblocks holding
 117  										 *   rsCtext */
 118  	
 119  	/*
 120  	 * temporary variables used for encrypt/decrypt. The values in these
 121  	 * are not needed to be kept from block to block; we just
 122  	 * alloc them once per lifetime of a feeFEED object as an optimization.
 123  	 */
 124  	giant 			xp;					/* plaintext */
 125  	giant			xm;					/* ciphertext */
 126  	giant			tmp1;				/* scratch */
 127  	giant			tmp2;				/* scratch */
 128  } feedInst;
 129  
 130  /*
 131   * "zero residue" indicator.
 132   */
 133  #define RESID_ZERO	0xff
 134  
 135  /*
 136   * cons up:
 137   * 	cluePlus(0)
 138   *	clueMinus(0)
 139   *	sPlus
 140   *	sMinus
 141   *	r
 142   * Assumes:
 143   *	cluePlus = clueMinus = ourPriv * theirPub
 144   *	initialRS
 145   * 	initialRSSize
 146   *	cp
 147   *
 148   * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting
 149   * first block of data.
 150   */
 151  static feeReturn initFromRS(feedInst *finst)
 152  {
 153  	giant s;
 154  	unsigned rSize = finst->initialRSSize / 2;
 155  
 156  	#if	FEED_DEBUG
 157  	if((finst->initialRS == NULL) ||
 158  	   (finst->cp == NULL) ||
 159  	   (finst->cluePlus == NULL) ||
 160  	   (finst->clueMinus == NULL) ||
 161  	   (finst->initialRSSize == 0)) {
 162  	    	dbgLog(("initFromRS: resource shortage\n"));
 163  	    	return FR_Internal;
 164  	}
 165  	#endif	// FEED_DEBUG
 166  
 167  	finst->r = giant_with_data(finst->initialRS, rSize);
 168  	s = giant_with_data(finst->initialRS+rSize, rSize);
 169  
 170  	#if	FEED_DEBUG
 171  	if(isZero(finst->r)) {
 172  		printf("initFromRS: r = 0! initialRSSize = %d; encr = %s\n",
 173  			finst->initialRSSize,
 174  			(finst->rsCtext == NULL) ? "TRUE" : "FALSE");
 175  	}
 176  	if(isZero(s)) {
 177  		printf("initFromRS: s = 0! initialRSSize = %d; encr = %s\n",
 178  			finst->initialRSSize,
 179  			(finst->rsCtext == NULL) ? "TRUE" : "FALSE");
 180  	}
 181  	#endif	// FEE_DEBUG
 182  	/*
 183  	 * Justify r and s to be in [2, minimumX1Order].
 184  	 */
 185  	lesserX1OrderJustify(finst->r, finst->cp);
 186  	lesserX1OrderJustify(s, finst->cp);
 187  
 188  	/*
 189  	 * sPlus  = s * x1Plus
 190  	 * sMinus = s * x1Minus
 191  	 */
 192  	finst->sPlus = newGiant(finst->cp->maxDigits);
 193  	finst->sMinus = newGiant(finst->cp->maxDigits);
 194  	gtog(finst->cp->x1Plus, finst->sPlus);
 195  	elliptic_simple(finst->sPlus, s, finst->cp);
 196  	gtog(finst->cp->x1Minus, finst->sMinus);
 197  	elliptic_simple(finst->sMinus, s, finst->cp);
 198  
 199  	/*
 200  	 * And finally, the initial clues. They are currently set to
 201  	 * ourPriv * theirPub.
 202  	 */
 203  	#if	FEED_DEBUG
 204  	printf("cluePlus : "); printGiant(finst->cluePlus);
 205  	printf("clueMinus: "); printGiant(finst->clueMinus);
 206  	#endif	// FEED_EEBUG
 207  
 208  	elliptic_simple(finst->cluePlus, finst->r, finst->cp);
 209  	elliptic_simple(finst->clueMinus, finst->r, finst->cp);
 210  
 211  	#if	FEED_DEBUG
 212  	printf("r        : "); printGiant(finst->r);
 213  	printf("s        : "); printGiant(s);
 214  	printf("sPlus    : "); printGiant(finst->sPlus);
 215  	printf("sMinus   : "); printGiant(finst->sMinus);
 216  	printf("cluePlus : "); printGiant(finst->cluePlus);
 217  	printf("clueMinus: "); printGiant(finst->clueMinus);
 218  	#endif	// FEED_DEBUG
 219  
 220  	freeGiant(s);
 221  	return FR_Success;
 222  }
 223  
 224  /*
 225   * Alloc and init a feeFEED object associated with specified public and
 226   * private keys.
 227   */
 228  feeFEED feeFEEDNewWithPubKey(feePubKey myPrivKey,
 229  	feePubKey theirPubKey,
 230  	int forEncrypt,			// 0 ==> decrypt   1 ==> encrypt
 231  	feeRandFcn randFcn,		// optional 
 232  	void *randRef)
 233  {
 234  	feedInst 		*finst;
 235  	giant			privGiant;
 236  	key				k;
 237  	unsigned 		expPlainSize;
 238  	unsigned 		expCipherSize;
 239  	unsigned 		expBlocks;
 240  
 241  	if(!curveParamsEquivalent(feePubKeyCurveParams(theirPubKey),
 242  		    feePubKeyCurveParams(myPrivKey))) {
 243  		dbgLog(("feeFEEDNewWithPubKey: Incompatible Keys\n"));
 244  		return NULL;
 245  	}
 246  	finst = (feedInst*) fmalloc(sizeof(feedInst));
 247  	bzero(finst, sizeof(feedInst));
 248  	finst->forEncrypt = forEncrypt;
 249  	finst->cp = curveParamsCopy(feePubKeyCurveParams(theirPubKey));
 250  	finst->rsBlockCount = 0;
 251  	finst->xp = newGiant(finst->cp->maxDigits);
 252  	finst->xm = newGiant(finst->cp->maxDigits);
 253  	finst->tmp1 = newGiant(finst->cp->maxDigits);
 254  	if(forEncrypt) {
 255  	    finst->tmp2 = newGiant(finst->cp->maxDigits);
 256  	}
 257  
 258  	/*
 259  	 * cluePlus  = ourPriv * theirPub+
 260  	 * clueMinus = ourPriv * theirPub-
 261  	 */
 262  	finst->cluePlus  = newGiant(finst->cp->maxDigits);
 263  	finst->clueMinus = newGiant(finst->cp->maxDigits);
 264  	privGiant = feePubKeyPrivData(myPrivKey);
 265  	if(privGiant == NULL) {
 266  		dbgLog(("feeFEEDNewWithPubKey: no private key\n"));
 267  		goto abort;
 268  	}
 269  	k = feePubKeyPlusCurve(theirPubKey);
 270  	gtog(k->x, finst->cluePlus);			// cluePlus = theirPub+
 271  	elliptic_simple(finst->cluePlus, privGiant, finst->cp);
 272  	k = feePubKeyMinusCurve(theirPubKey);
 273  	gtog(k->x, finst->clueMinus);			// theirPub-
 274  	elliptic_simple(finst->clueMinus, privGiant, finst->cp);
 275  
 276  	/*
 277  	 * Set up block sizes.
 278  	 */
 279  	if(finst->cp->primeType == FPT_General) {
 280  	    unsigned blen = bitlen(finst->cp->basePrime);
 281  
 282  	    finst->plainBlockSize = blen / 8;
 283  	    if((blen & 0x7) == 0) {
 284  	    	/*
 285  		 * round down some more...
 286  		 */
 287  		finst->plainBlockSize--;
 288  	    }
 289  	}
 290  	else {
 291  	    finst->plainBlockSize = finst->cp->q / 8;
 292  	    if(((finst->cp->q & 0x7) == 0) && (finst->cp->k > 0)) {
 293  		/*
 294  		 * Special case, with q mod 8 == 0. Here we have to
 295  		 * trim back the plainBlockSize by one byte.
 296  		 */
 297  		finst->plainBlockSize--;
 298  	    }
 299  	}
 300  	finst->cipherBlockSize = finst->cp->minBytes + 1;
 301  
 302  	/*
 303  	 * the size of initialRS is subject to tweaking - if we make it
 304  	 * not a multiple of plainBlockSize, we save one FEEDExp cipherBlock
 305  	 * in our ciphertext.
 306  	 */
 307  	finst->initialRSSize = finst->plainBlockSize * 2;
 308  	if(finst->initialRSSize > RS_MIN_SIZE) {
 309  	    unsigned minPlainBlocks;
 310  	    unsigned maxSize;
 311  
 312  	    /*
 313  	     * How many plainblocks to hold RS_MIN_SIZE?
 314  	     */
 315  	    minPlainBlocks = (RS_MIN_SIZE + finst->plainBlockSize - 1) /
 316  	    	finst->plainBlockSize;
 317  
 318  	    /*
 319  	     * Max size = that many plainblocks, less 2 bytes (to avoid
 320  	     * extra residue block).
 321  	     */
 322  	    maxSize = minPlainBlocks * finst->plainBlockSize - 2;
 323  
 324  	    /*
 325  	     * But don't bother with more than 2 plainblocks worth
 326  	     */
 327  	    if(finst->initialRSSize > maxSize) {
 328  	        finst->initialRSSize = maxSize;
 329  	    }
 330  	}
 331  	/* else leave it alone, that's small enough */
 332  
 333  	if(forEncrypt) {
 334  		feeRand frand = NULL;
 335  
 336  		/*
 337  		 * Encrypt-capable FEEDExp object
 338  		 */
 339  		finst->feedExp = feeFEEDExpNewWithPubKey(theirPubKey,
 340  			randFcn,
 341  			randRef);
 342  		if(finst->feedExp == NULL) {
 343  			goto abort;
 344  		}
 345  
 346  		/*
 347  		 * Generate initial r and s data.
 348  		 */
 349  		finst->initialRS = (unsigned char*) fmalloc(finst->initialRSSize);
 350  		if(randFcn != NULL) {
 351  			randFcn(randRef, finst->initialRS, finst->initialRSSize);
 352  		}
 353  		else {
 354  			frand = feeRandAlloc();
 355  			feeRandBytes(frand, finst->initialRS, finst->initialRSSize);
 356  			feeRandFree(frand);
 357  		}
 358  		if(initFromRS(finst)) {
 359  			goto abort;
 360  		}
 361  	}
 362  	else {
 363  		/*
 364  		 * Decrypt-capable FEEDExp object
 365  		 */
 366  		finst->feedExp = feeFEEDExpNewWithPubKey(myPrivKey,
 367  			randFcn,
 368  			randRef);
 369  		if(finst->feedExp == NULL) {
 370  			goto abort;
 371  		}
 372  
 373  	}
 374  
 375  	/*
 376  	 * Figure out how many of our cipherblocks it takes to hold
 377  	 * a FEEDExp-encrypted initialRS. If initialRSSize is an exact
 378  	 * multiple of expPlainSize, we get an additional feedExp
 379  	 * residue block.
 380  	 */
 381  	expPlainSize = feeFEEDExpPlainBlockSize(finst->feedExp);
 382  	expCipherSize = feeFEEDExpCipherBlockSize(finst->feedExp);
 383  	expBlocks = (finst->initialRSSize + expPlainSize - 1) /
 384  		expPlainSize;
 385  	if((finst->initialRSSize % expPlainSize) == 0) {
 386  		expBlocks++;
 387  	}
 388  
 389  	/*
 390  	 * Total meaningful bytes of encrypted initialRS
 391  	 */
 392  	finst->rsCtextSize = expBlocks * expCipherSize;
 393  
 394  	/*
 395  	 * Number of our cipherblocks it takes to hold rsCtextSize
 396  	 */
 397  	finst->rsSizeCipherBlocks = (finst->rsCtextSize +
 398  		finst->cipherBlockSize - 1) / finst->cipherBlockSize;
 399  	if(!forEncrypt) {
 400  	    finst->rsCtext = (unsigned char*) fmalloc(finst->rsSizeCipherBlocks *
 401  		finst->cipherBlockSize);
 402  	}
 403  
 404  	/*
 405  	 * Sanity check...
 406  	 */
 407  	#if	FEED_DEBUG
 408  	{
 409  	    unsigned fexpBlockSize = feeFEEDExpCipherBlockSize(finst->feedExp);
 410  
 411  	    /*
 412  	     * FEEDExp has one more giant in ciphertext, plaintext is
 413  	     * same size
 414  	     */
 415  	    if((finst->cipherBlockSize + finst->cp->minBytes) !=
 416  			fexpBlockSize) {
 417  		dbgLog(("feeFEEDNewWithPubKey: FEEDExp CBlock Size "
 418  			"screwup\n"));
 419  		goto abort;
 420  	    }
 421  	    fexpBlockSize = feeFEEDExpPlainBlockSize(finst->feedExp);
 422  	    if(fexpBlockSize != finst->plainBlockSize) {
 423  		dbgLog(("feeFEEDNewWithPubKey: FEEDExp PBlock Size "
 424  			"screwup\n"));
 425  		goto abort;
 426  	    }
 427  	}
 428  	#endif	// FEED_DEBUG
 429  
 430  	return finst;
 431  
 432  abort:
 433  	feeFEEDFree(finst);
 434  	return NULL;
 435  }
 436  
 437  void feeFEEDFree(feeFEED feed)
 438  {
 439  	feedInst *finst = (feedInst*) feed;
 440  
 441  	if(finst->cp) {
 442  		freeCurveParams(finst->cp);
 443  	}
 444  	if(finst->initialRS) {
 445  		ffree(finst->initialRS);
 446  	}
 447  	if(finst->cluePlus) {
 448  		freeGiant(finst->cluePlus);
 449  	}
 450  	if(finst->clueMinus) {
 451  		freeGiant(finst->clueMinus);
 452  	}
 453  	if(finst->sPlus) {
 454  		freeGiant(finst->sPlus);
 455  	}
 456  	if(finst->sMinus) {
 457  		freeGiant(finst->sMinus);
 458  	}
 459  	if(finst->r) {
 460  		freeGiant(finst->r);
 461  	}
 462  	if(finst->feedExp) {
 463  		feeFEEDExpFree(finst->feedExp);
 464  	}
 465  	if(finst->rsCtext) {
 466  		ffree(finst->rsCtext);
 467  	}
 468  	if(finst->xp) {
 469  		freeGiant(finst->xp);
 470  	}
 471  	if(finst->xm) {
 472  		freeGiant(finst->xm);
 473  	}
 474  	if(finst->tmp1) {
 475  		freeGiant(finst->tmp1);
 476  	}
 477  	if(finst->tmp2) {
 478  		freeGiant(finst->tmp2);
 479  	}
 480  	ffree(finst);
 481  }
 482  
 483  unsigned feeFEEDPlainBlockSize(feeFEED feed)
 484  {
 485  	feedInst *finst = (feedInst *) feed;
 486  
 487  	return finst->plainBlockSize;
 488  }
 489  
 490  unsigned feeFEEDCipherBlockSize(feeFEED feed)
 491  {
 492  	feedInst *finst = (feedInst *) feed;
 493  
 494  	return finst->cipherBlockSize;
 495  }
 496  
 497  /*
 498   * Calculate size of buffer currently needed to encrypt one block of
 499   * plaintext. Also used to calculate required input during decrypt
 500   * to get any output.
 501   */
 502  unsigned feeFEEDCipherBufSize(feeFEED feed,
 503  	 int finalBlock)
 504  {
 505  	feedInst *finst = (feedInst *) feed;
 506  	unsigned blocks = 1;			// always at least one block of ciphertext
 507  	
 508  	if(finst->rsBlockCount == 0) {
 509  		/* haven't sent/seen encrypted RS yet */
 510  		blocks += finst->rsSizeCipherBlocks;
 511  	}
 512  	
 513  	if(finalBlock) {
 514  		/* only needed if ptext is aligned, but tell caller to malloc */
 515  		blocks++;
 516  	}
 517  	bprintf(("$$$ feeFEEDCipherBufSize( %s, %s): rtn 0x%x\n",
 518  		finst->forEncrypt ? "encrypt" : "decrypt",
 519  		finalBlock ? " final" : "!final", 
 520  		blocks * finst->cipherBlockSize));
 521  	return blocks * finst->cipherBlockSize;
 522  }
 523  
 524  /*
 525   * Return the size of ciphertext currently needed to encrypt specified 
 526   * size of plaintext. Also can be used to calculate size of ciphertext 
 527   * which can be decrypted into specified size of plaintext. 
 528   */
 529  unsigned feeFEEDCipherTextSize(feeFEED feed, 
 530  	unsigned 	plainTextSize,
 531  	int 		finalBlock)
 532  {
 533  	feedInst *finst = (feedInst *) feed;
 534  	
 535  	/* how many blocks of plaintext? */
 536  	unsigned blocks = (plainTextSize + finst->plainBlockSize - 1) /
 537  		finst->plainBlockSize;
 538  
 539  	if(finst->forEncrypt) {
 540  		/* have we generated RS? */
 541  		if(finst->rsBlockCount == 0) {
 542  			/* haven't sent encrypted RS yet */
 543  			blocks += finst->rsSizeCipherBlocks;
 544  		}
 545  	
 546  		/* final? residue? */
 547  		if(finalBlock) {
 548  			if((plainTextSize % finst->plainBlockSize) == 0) {
 549  				blocks++;
 550  			}
 551  		}
 552  	}	/* encrypting */
 553  	else {
 554  		/* 
 555  		 * Decrypting - how much ciphertext can we decrypt safely into
 556  		 * specified plaintext? Add in RS if we haven't seen it all
 557  		 * yet.
 558  		 */
 559  		#if BUFFER_DEBUG
 560  		if(finst->rsBlockCount > finst->rsSizeCipherBlocks) {
 561  			printf("******HEY! rsBlockCount overflow! (blockCount %d rsSize %d)\n",
 562  				finst->rsBlockCount, finst->rsSizeCipherBlocks);
 563  		}
 564  		#endif
 565  		blocks += (finst->rsSizeCipherBlocks - finst->rsBlockCount);
 566  	}
 567  	bprintf(("$$$ feeFEEDCipherTextSize(%s, %s, 0x%x): rtn 0x%x\n",
 568  		finst->forEncrypt ? "encrypt" : "decrypt",
 569  		finalBlock ? " final" : "!final", 
 570  		plainTextSize, blocks * finst->cipherBlockSize));
 571  	return blocks * finst->cipherBlockSize;
 572  }
 573  
 574  /*
 575   * Return the size of plaintext currently needed to decrypt specified size 
 576   * of ciphertext. Also can be used to calculate size of plaintext 
 577   * which can be encrypted into specified size of ciphertext.
 578   */
 579  unsigned feeFEEDPlainTextSize(feeFEED feed, 
 580  	unsigned 	cipherTextSize,
 581  	int 		finalBlock)			// ignored if !forEncrypt
 582  {
 583  	feedInst *finst = (feedInst *) feed;
 584  	
 585  	/* start with basic cipher block count */
 586  	unsigned cipherBlocks = (cipherTextSize + finst->cipherBlockSize - 1) /
 587  		finst->cipherBlockSize;
 588  		
 589  	/* where are we in the RS stream? */
 590  	unsigned rsBlocksToGo = finst->rsSizeCipherBlocks - finst->rsBlockCount;
 591  	if(finst->forEncrypt) {
 592  		/* 
 593  		 * Encrypting, seeking plaintext size we can encrypt given
 594  		 * a specified size of ciphertext.
 595  		 */
 596  		if(rsBlocksToGo >= cipherBlocks) {
 597  			/* no room! next encrypt would overflow ctext buffer! */
 598  			return 0;
 599  		}
 600  		cipherBlocks -= rsBlocksToGo;
 601  		
 602  		/* another constraint - residue */
 603  		if(finalBlock) {
 604  			if(cipherBlocks) {
 605  				/* skip if already zero... */
 606  				cipherBlocks--;
 607  			}
 608  		}
 609  	}	/* encrypting */
 610  	else {
 611  		/* decrypting */
 612  		if(rsBlocksToGo >= cipherBlocks) {
 613  			/* still processing RS, no plaintext will be generated. Play it real
 614  			 * safe and just tell caller one block. */
 615  			cipherBlocks = 1;
 616  		}
 617  		else {
 618  			/* diminish by size of RS to be gobbled with no output */
 619  			cipherBlocks -= rsBlocksToGo;
 620  		}
 621  	}
 622  	bprintf(("$$$ feeFEEDPlainTextSize( %s, %s, 0x%x): rtn 0x%x\n",
 623  		finst->forEncrypt ? "encrypt" : "decrypt",
 624  		finalBlock ? " final" : "!final", 
 625  		cipherTextSize, cipherBlocks * finst->plainBlockSize));
 626  	return cipherBlocks * finst->plainBlockSize;
 627  }
 628  
 629  /*
 630   * Bits in last byte of cipherblock
 631   */
 632  #define CLUE_BIT		0x01	/* 1 ==> plus curve */
 633  #define CLUE_PLUS		0x01
 634  #define CLUE_MINUS		0x00
 635  #define PARITY_BIT		0x02	/* 1 ==> plus 's' arg to elliptic_add() */
 636  #define PARITY_PLUS		0x02
 637  #define PARITY_MINUS	0x00
 638  
 639  /*
 640   * Encrypt a block or less of data. Caller malloc's cipherText.
 641   * Generates up to feeFEEDCipherBufSize() bytes of ciphertext.
 642   */
 643  feeReturn feeFEEDEncryptBlock(feeFEED feed,
 644  	const unsigned char *plainText,
 645  	unsigned plainTextLen,
 646  	unsigned char *cipherText,
 647  	unsigned *cipherTextLen,		// RETURNED
 648  	int finalBlock)
 649  {
 650  	feedInst 		*finst = (feedInst *) feed;
 651  	unsigned		ctextLen = 0;
 652  	feeReturn		frtn = FR_Success;
 653  	int				whichCurve;
 654  	giant			thisClue;		// not alloc'd or freed
 655  	giant			thisS;			// ditto
 656  	unsigned char	clueByte;
 657  
 658  	if(plainTextLen > finst->plainBlockSize) {
 659  		return FR_IllegalArg;
 660  	}
 661  	if((plainTextLen < finst->plainBlockSize) && !finalBlock) {
 662  		return FR_IllegalArg;
 663  	}
 664  	if(finst->initialRS == NULL) {
 665  		/*
 666  		 * Init'd for decrypt?
 667  		 */
 668  		return FR_IllegalArg;
 669  	}
 670  
 671  	/*
 672  	 * First block - encrypt initialRS via FEEDExp
 673  	 */
 674  	if(finst->rsBlockCount == 0) {
 675  	    unsigned char *thisCtext;	// malloc's by FEEDExp
 676  	    unsigned padLen;
 677  
 678  	    if(finst->initialRS == NULL) {
 679  		/*
 680  		 * init'd for decrypt or reused
 681  		 */
 682  		dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n"));
 683  		return FR_IllegalArg;
 684  	    }
 685  
 686  	    frtn = feeFEEDExpEncrypt(finst->feedExp,
 687  		    finst->initialRS,
 688  		    finst->initialRSSize,
 689  		    &thisCtext,
 690  		    &ctextLen);
 691  	    if(frtn) {
 692  		    /*
 693  		     * Should never happen...
 694  		     */
 695  		    dbgLog(("feeFEEDEncryptBlock: error writing encrypted"
 696  			    " initialRS (%s)\n", feeReturnString(frtn)));
 697  		    return FR_Internal;
 698  	    }
 699  	    bcopy(thisCtext, cipherText, ctextLen);
 700  	    cipherText += ctextLen;
 701  	    ffree(thisCtext);
 702  
 703  	    finst->rsBlockCount = finst->rsSizeCipherBlocks;
 704  	    padLen = finst->cipherBlockSize -
 705  	    	(ctextLen % finst->cipherBlockSize);	// zeros to write
 706  
 707  	    #if		0	/* FEED_DEBUG */
 708  
 709  	    /*
 710  	     * Hard-coded assumptions and tests about initRSSize...
 711  	     * Currently we assume that initRSSize % expBlockSize = 0
 712  	     */
 713  	    if((ctextLen / finst->cipherBlockSize) != 5) {
 714  		dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (1)\n"));
 715  		return FR_Internal;
 716  	    }
 717  	    if(padLen != 3) {
 718  		dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (2)\n"));
 719  		return FR_Internal;
 720  	    }
 721  	    #endif	// FEED_DEBUG
 722  
 723  	    /*
 724  	     * pad to multiple of (our) cipherblock size.
 725  	     */
 726  	    while(padLen) {
 727  		*cipherText++ = 0;
 728  		ctextLen++;
 729  		padLen--;
 730  	    }
 731  	}
 732  
 733  	/*
 734  	 * plaintext to giant xp
 735  	 */
 736  	if(finalBlock) {
 737  		unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize);
 738  		bzero(ptext, finst->plainBlockSize);
 739  		if(plainTextLen) {
 740  			/*
 741  			 * skip for empty block with resid length 0
 742  			 */
 743  			bcopy(plainText, ptext, plainTextLen);
 744  		}
 745  		if(plainTextLen < finst->plainBlockSize) {
 746  		    if(plainTextLen == 0) {
 747  		    	/*
 748  			 * Special case - resid block with no actual plaintext.
 749  			 * Can't actually write zero here; it screws up
 750  			 * deserializing the giant during decrypt
 751  			 */
 752  		        ptext[finst->plainBlockSize - 1] = RESID_ZERO;
 753  				bprintf(("=== FEED encrypt: RESID_ZERO\n"));
 754  		    }
 755  		    else {
 756  				ptext[finst->plainBlockSize - 1] = plainTextLen;
 757  				bprintf(("=== FEED encrypt: resid len 0x%x\n", plainTextLen));
 758  		    }
 759  		}
 760  		/*
 761  		 * else handle evenly aligned case (i.e., finalBlock true
 762  		 * and (plainTextLen ==  plainBlockSize)) below...
 763  		 */
 764  		deserializeGiant(ptext, finst->xp, finst->plainBlockSize);
 765  		ffree(ptext);
 766  	}
 767  	else {
 768  		deserializeGiant(plainText, finst->xp, plainTextLen);
 769  	}
 770  
 771  	/*
 772  	 * encrypt xp
 773  	 *     xm = xp + clue(+/-)
 774  	 * determine parity needed to restore xp
 775  	 *     parity = ((xm + clue(+/-) == xp) ? 1 : -1
 776  	 * and adjust clue
 777  	 *     clue[n+1] = r * clue[n] + (s * P1)
 778  	 */
 779  	whichCurve = which_curve(finst->xp, finst->cp);
 780  	if(whichCurve == CURVE_PLUS) {
 781  		thisClue = finst->cluePlus;
 782  		thisS    = finst->sPlus;
 783  		clueByte = CLUE_PLUS;
 784  	}
 785  	else {
 786  		thisClue = finst->clueMinus;
 787  		thisS    = finst->sMinus;
 788  		clueByte = CLUE_MINUS;
 789  	}
 790  	// calculate xm
 791  	elliptic_add(thisClue, finst->xp, finst->xm, finst->cp, SIGN_PLUS);
 792  	// save xm + clue in tmp1
 793  	elliptic_add(finst->xm, thisClue, finst->tmp1, finst->cp, SIGN_PLUS);
 794  	// Adjust clue
 795  	elliptic_simple(thisClue, finst->r, finst->cp);
 796  	gtog(thisClue, finst->tmp2);
 797  	elliptic_add(finst->tmp2, thisS, thisClue, finst->cp, SIGN_PLUS);
 798  
 799  	/*
 800  	 * Calculate parity
 801  	 */
 802  	if(gcompg(finst->tmp1, finst->xp) == 0) {
 803  		clueByte |= PARITY_PLUS;
 804  	}
 805  
 806  	/*
 807  	 * Ciphertext = (xm, clueByte)
 808  	 */
 809  	serializeGiant(finst->xm, cipherText, finst->cp->minBytes);
 810  	cipherText += finst->cp->minBytes;
 811  	ctextLen += finst->cp->minBytes;
 812  	*cipherText++ = clueByte;
 813  	ctextLen++;
 814  
 815  	#if	FEED_DEBUG
 816  	printf("encrypt  clue %d\n", clueByte);
 817  	printf("  xp : "); printGiant(finst->xp);
 818  	printf("  xm : "); printGiant(finst->xm);
 819  	printf("  cluePlus  :"); printGiant(finst->cluePlus);
 820  	printf("  clueMinus :"); printGiant(finst->clueMinus);
 821  	#endif	// FEED_DEBUG
 822  
 823  	if(finalBlock && (plainTextLen == finst->plainBlockSize)) {
 824  	       /*
 825  		* Special case: finalBlock true, plainTextLen == blockSize.
 826  		* In this case we generate one more block of ciphertext,
 827  		* with a resid length of zero.
 828  		*/
 829  		unsigned moreCipher;			// additional cipherLen
 830  
 831  		frtn = feeFEEDEncryptBlock(feed,
 832  			NULL,				// plainText not used
 833  			0,				// resid
 834  			cipherText,			// append...
 835  			&moreCipher,
 836  			1);
 837  		if(frtn == FR_Success) {
 838  			ctextLen += moreCipher;
 839  		}
 840  	}
 841  	bprintf(("=== FEED encryptBlock ptextLen 0x%x  ctextLen 0x%x\n",
 842  		plainTextLen, ctextLen));
 843  		
 844  	*cipherTextLen = ctextLen;
 845  	return frtn;
 846  }
 847  
 848  /*
 849   * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
 850   * generates feeFEEDPlainBlockSize of plaintext, unless finalBlock is
 851   * non-zero (in which case feeFEEDPlainBlockSize or less bytes of plainText are
 852   * generated).
 853   */
 854  feeReturn feeFEEDDecryptBlock(feeFEED feed,
 855  	const unsigned char *cipherText,
 856  	unsigned cipherTextLen,
 857  	unsigned char *plainText,
 858  	unsigned *plainTextLen,			// RETURNED
 859  	int finalBlock)
 860  {
 861  	feedInst 	*finst = (feedInst *) feed;
 862  	feeReturn	frtn = FR_Success;
 863  	unsigned char	clueByte;
 864  	giant		thisClue;		// not alloc'd
 865  	giant		thisS;			// ditto
 866  	int 		parity;
 867  
 868  	if(finst->rsCtext == NULL) {
 869  		/*
 870  		 * Init'd for encrypt?
 871  		 */
 872  		return FR_IllegalArg;
 873  	}
 874  	if(cipherTextLen != finst->cipherBlockSize) {
 875  	 	dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n"));
 876  		return FR_IllegalArg;
 877  	}
 878  	if(finst->rsBlockCount < finst->rsSizeCipherBlocks) {
 879  		/*
 880  		 * Processing initialRS, FEEDExp-encrypted
 881  		 */
 882  		unsigned char *rsPtr = finst->rsCtext +
 883  			(finst->rsBlockCount * finst->cipherBlockSize);
 884  		unsigned feedExpCipherSize;
 885  
 886  		if(finalBlock) {
 887  		    dbgLog(("feeFEEDDecryptBlock: incomplete initialRS\n"));
 888  		    return FR_BadCipherText;
 889  		}
 890  		bcopy(cipherText, rsPtr, finst->cipherBlockSize);
 891  		finst->rsBlockCount++;
 892  		if(finst->rsBlockCount < finst->rsSizeCipherBlocks) {
 893  		    /*
 894  		     * Not done with this yet...
 895  		     */
 896  			bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (1)\n", 
 897  				cipherTextLen));
 898  		    *plainTextLen = 0;
 899  		    return FR_Success;
 900  		}
 901  
 902  		#if	FEED_DEBUG
 903  		if((finst->rsBlockCount * finst->cipherBlockSize) <
 904  				finst->rsCtextSize) {
 905  		    dbgLog(("feeFEEDDecryptBlock: rsCtextSize underflow!\n"));
 906  		    return FR_Internal;
 907  		}
 908  		#endif	// FEED_DEBUG
 909  
 910  		/*
 911  		 * OK, we should have the FEEDExp ciphertext for initialRS
 912  		 * in rsCtext. Note the last few bytes are extra; we don't
 913  		 * pass them to FEEDExp.
 914  		 */
 915  		feedExpCipherSize = feeFEEDCipherBlockSize(finst->feedExp);
 916  		frtn = feeFEEDExpDecrypt(finst->feedExp,
 917  			finst->rsCtext,
 918  			finst->rsCtextSize,
 919  			&finst->initialRS,
 920  			&finst->initialRSSize);
 921  		if(frtn) {
 922     		    dbgLog(("feeFEEDDecryptBlock: error decrypting "
 923  		    	"initialRS (%s)\n", feeReturnString(frtn)));
 924  		    return FR_BadCipherText;
 925  		}
 926  
 927  		/*
 928  		 * Set up clues
 929  		 */
 930  		if(initFromRS(finst)) {
 931     		    dbgLog(("feeFEEDDecryptBlock: bad initialRS\n"));
 932  		    return FR_BadCipherText;
 933  		}
 934  		else {
 935  		    /*
 936  		     * Normal completion of last cipherblock containing
 937  		     * initialRS.
 938  		     */
 939  			bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n", 
 940  				cipherTextLen));
 941  		    *plainTextLen = 0;
 942  		    return FR_Success;
 943  		}
 944  	}
 945  
 946  	/*
 947  	 * grab xm and clueByte from cipherText
 948  	 */
 949  	deserializeGiant(cipherText, finst->xm, finst->cp->minBytes);
 950  	cipherText += finst->cp->minBytes;
 951  	clueByte = *cipherText;
 952  
 953  	if((clueByte & CLUE_BIT) == CLUE_PLUS) {
 954  		thisClue = finst->cluePlus;
 955  		thisS = finst->sPlus;
 956  	}
 957  	else {
 958  		thisClue = finst->clueMinus;
 959  		thisS = finst->sMinus;
 960  	}
 961  	if((clueByte & PARITY_BIT) == PARITY_PLUS) {
 962  		parity = SIGN_PLUS;
 963  	}
 964  	else {
 965  		parity = SIGN_MINUS;
 966  	}
 967  
 968  	/*
 969  	 * recover xp
 970  	 *     xp = xm + clue(+/-) w/parity
 971  	 * adjust clue
 972  	 *     clue[n+1] = r * clue[n] + (s * P1)
 973  	 */
 974  	elliptic_add(thisClue, finst->xm, finst->xp, finst->cp, parity);
 975  
 976  	elliptic_simple(thisClue, finst->r, finst->cp);
 977  	gtog(thisClue, finst->tmp1);
 978  	elliptic_add(finst->tmp1, thisS, thisClue, finst->cp, SIGN_PLUS);
 979  
 980  	/*
 981  	 * plaintext in xp
 982  	 */
 983  	#if	FEED_DEBUG
 984  	printf("decrypt  clue %d\n", clueByte);
 985  	printf("  xp : "); printGiant(finst->xp);
 986  	printf("  xm : "); printGiant(finst->xm);
 987  	printf("  cluePlus  :"); printGiant(finst->cluePlus);
 988  	printf("  clueMinus :"); printGiant(finst->clueMinus);
 989  	#endif	// FEED_DEBUG
 990  
 991  	if(finalBlock) {
 992  		/*
 993  		 * Snag data from xp in order to find out how much to move to
 994  		 * *plainText
 995  		 */
 996  		unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize);
 997  
 998  		serializeGiant(finst->xp, ptext, finst->plainBlockSize);
 999  		*plainTextLen = ptext[finst->plainBlockSize - 1];
1000  		if(*plainTextLen == RESID_ZERO) {
1001  			bprintf(("=== FEED Decrypt: RESID_ZERO\n"));
1002  			*plainTextLen = 0;
1003  		}
1004  		else if(*plainTextLen > (finst->plainBlockSize - 1)) {
1005  			dbgLog(("feeFEEDDecryptBlock: ptext overflow!\n"));
1006  			bprintf(("feeFEEDDecryptBlock: ptext overflow!\n"));
1007  			frtn = FR_BadCipherText;
1008  		}
1009  		else {
1010  			bprintf(("=== FEED Decrypt: resid len 0x%x\n", *plainTextLen));
1011  			bcopy(ptext, plainText, *plainTextLen);
1012  		}
1013  		ffree(ptext);
1014  	}
1015  	else {
1016  		*plainTextLen = finst->plainBlockSize;
1017  		serializeGiant(finst->xp, plainText, *plainTextLen);
1018  	}
1019  	bprintf(("=== FEED decryptBlock ptextLen 0x%x  ctextLen 0x%x\n",
1020  		*plainTextLen, cipherTextLen));
1021  
1022  	return frtn;
1023  }
1024  
1025  /*
1026   * Convenience routines to encrypt & decrypt multi-block data.
1027   */
1028  feeReturn feeFEEDEncrypt(feeFEED feed,
1029  	const unsigned char *plainText,
1030  	unsigned plainTextLen,
1031  	unsigned char **cipherText,		// malloc'd and RETURNED
1032  	unsigned *cipherTextLen)		// RETURNED
1033  {
1034  	const unsigned char	*ptext;			// per block
1035  	unsigned			ptextLen;		// total to go
1036  	unsigned			thisPtextLen;		// per block
1037  	unsigned char		*ctext;			// per block
1038  	unsigned			ctextLen;		// per block
1039  	unsigned char		*ctextResult;		// to return
1040  	unsigned			ctextResultLen;		// size of ctextResult
1041  	unsigned char		*ctextPtr;
1042  	unsigned 			ctextLenTotal;		// running total
1043  	feeReturn			frtn;
1044  	int					finalBlock;
1045  	unsigned			numBlocks;
1046  	unsigned			plainBlockSize;
1047  	#if	FEE_DEBUG
1048  	unsigned		expectedCtextSize;
1049  
1050  	expectedCtextSize = feeFEEDCipherTextSize(feed, plainTextLen, 1);
1051  	#endif
1052  	
1053  	if(plainTextLen == 0) {
1054  		dbgLog(("feeFEEDDecrypt: NULL plainText\n"));
1055  		return FR_IllegalArg;
1056  	}
1057  
1058  	ptext = plainText;
1059  	ptextLen = plainTextLen;
1060  	ctext = (unsigned char*) fmalloc(feeFEEDCipherBufSize(feed, 1));
1061  	plainBlockSize = feeFEEDPlainBlockSize(feed);
1062  	numBlocks = (plainTextLen + plainBlockSize - 1)/plainBlockSize;
1063  
1064  	/*
1065  	 * Calculate the worst-case size needed to hold all of the ciphertext
1066  	 */
1067  	ctextResultLen = feeFEEDCipherTextSize(feed, plainTextLen, 1);
1068  	ctextResult = (unsigned char*) fmalloc(ctextResultLen);
1069  	ctextPtr = ctextResult;
1070  	ctextLenTotal = 0;
1071  
1072  	while(1) {
1073  		if(ptextLen <= plainBlockSize) {
1074  			finalBlock = 1;
1075  			thisPtextLen = ptextLen;
1076  		}
1077  		else {
1078  			finalBlock = 0;
1079  			thisPtextLen = plainBlockSize;
1080  		}
1081  		frtn = feeFEEDEncryptBlock(feed,
1082  			ptext,
1083  			thisPtextLen,
1084  			ctext,
1085  			&ctextLen,
1086  			finalBlock);
1087  		if(frtn) {
1088  			dbgLog(("feeFEEDEncrypt: encrypt error: %s\n",
1089  				feeReturnString(frtn)));
1090  			break;
1091  		}
1092  		if(ctextLen == 0) {
1093  			dbgLog(("feeFEEDEncrypt: null ciphertext\n"));
1094  			frtn = FR_Internal;
1095  			break;
1096  		}
1097  		bcopy(ctext, ctextPtr, ctextLen);
1098  		ctextLenTotal += ctextLen;
1099  		if(ctextLenTotal > ctextResultLen) {
1100  			dbgLog(("feeFEEDEncrypt: ciphertext overflow\n"));
1101  			frtn = FR_Internal;
1102  			break;
1103  		}
1104  		if(finalBlock) {
1105  			break;
1106  		}
1107  		ctextPtr += ctextLen;
1108  		ptext += thisPtextLen;
1109  		ptextLen -= thisPtextLen;
1110  	}
1111  
1112  	ffree(ctext);
1113  	if(frtn) {
1114  		ffree(ctextResult);
1115  		*cipherText = NULL;
1116  		*cipherTextLen = 0;
1117  	}
1118  	else {
1119  		*cipherText = ctextResult;
1120  		*cipherTextLen = ctextLenTotal;
1121  		#if	FEE_DEBUG
1122  		if(expectedCtextSize != ctextLenTotal) {
1123  		    printf("feeFEEDEncrypt: feeFEEDCipherTextSize error!\n");
1124  		    printf("ptext %d  exp ctext %d  actual ctext %d\n",
1125  		    	plainTextLen,
1126  			expectedCtextSize,
1127  			ctextLenTotal);
1128  		}
1129  		#endif	// FEE_DEBUG
1130  	}
1131  	return frtn;
1132  
1133  }
1134  
1135  feeReturn feeFEEDDecrypt(feeFEED feed,
1136  	const unsigned char *cipherText,
1137  	unsigned cipherTextLen,
1138  	unsigned char **plainText,		// malloc'd and RETURNED
1139  	unsigned *plainTextLen)			// RETURNED
1140  {
1141  	const unsigned char	*ctext;
1142  	unsigned		ctextLen;		// total to go
1143  	unsigned char		*ptext;			// per block
1144  	unsigned		ptextLen;		// per block
1145  	unsigned char		*ptextResult;		// to return
1146  	unsigned char		*ptextPtr;
1147  	unsigned 		ptextLenTotal;		// running total
1148  	feeReturn		frtn = FR_Success;
1149  	int			finalBlock;
1150  	unsigned		numBlocks;
1151  	unsigned		plainBlockSize = feeFEEDPlainBlockSize(feed);
1152  	unsigned		cipherBlockSize = feeFEEDCipherBlockSize(feed);
1153  
1154  	if(cipherTextLen % cipherBlockSize) {
1155  		dbgLog(("feeFEEDDecrypt: unaligned cipherText\n"));
1156  		return FR_BadCipherText;
1157  	}
1158  	if(cipherTextLen == 0) {
1159  		dbgLog(("feeFEEDDecrypt: NULL cipherText\n"));
1160  		return FR_BadCipherText;
1161  	}
1162  
1163  	ptext = (unsigned char*) fmalloc(plainBlockSize);
1164  	ctext = cipherText;
1165  	ctextLen = cipherTextLen;
1166  	numBlocks = cipherTextLen / cipherBlockSize;
1167  	ptextResult = (unsigned char*) fmalloc(plainBlockSize * numBlocks);
1168  	ptextPtr = ptextResult;
1169  	ptextLenTotal = 0;
1170  
1171  	while(ctextLen) {
1172  		if(ctextLen == cipherBlockSize) {
1173  		    finalBlock = 1;
1174  		}
1175  		else {
1176  		    finalBlock = 0;
1177  		}
1178  		frtn = feeFEEDDecryptBlock(feed,
1179  			ctext,
1180  			cipherBlockSize,
1181  			ptext,
1182  			&ptextLen,
1183  			finalBlock);
1184  		if(frtn) {
1185  			dbgLog(("feeFEEDDecryptBlock: %s\n",
1186  				feeReturnString(frtn)));
1187  			break;
1188  		}
1189  		if(ptextLen) {
1190  			if(ptextLen > plainBlockSize) {
1191  			    dbgLog(("feeFEEDDecrypt: ptext overflow!\n"));
1192  			    frtn = FR_Internal;
1193  			    break;
1194  			}
1195  			bcopy(ptext, ptextPtr, ptextLen);
1196  			ptextPtr += ptextLen;
1197  			ptextLenTotal += ptextLen;
1198  		}
1199  		/*
1200  		 * note ptextLen == 0 is normal termination case for
1201  		 * plainTextLen % plainBlockSize == 0.
1202  		 * Also expected for first 4 blocks of ciphertext;
1203  		 * proceed (we break when ctextLen is exhausted).
1204  		 */
1205  		ctext += cipherBlockSize;
1206  		ctextLen -= cipherBlockSize;
1207  	}
1208  
1209  	ffree(ptext);
1210  	if(frtn) {
1211  		ffree(ptextResult);
1212  		*plainText = NULL;
1213  		*plainTextLen = 0;
1214  	}
1215  	else {
1216  		*plainText = ptextResult;
1217  		*plainTextLen = ptextLenTotal;
1218  	}
1219  	return frtn;
1220  
1221  }
1222