feeReturn feeCreateECDSAPrivBlob(feePubKey pubKey,
	unsigned char **keyBlob,
	unsigned *keyBlobLen)
{
	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
	if(pkinst == NULL) {
		return FR_BadPubKey;
	}
	if(pkinst->privGiant == NULL) {
		return FR_IncompatibleKey;
	}

	/* 
	 * Return the raw private key bytes padded with zeroes in
	 * the m.s. end to fill exactly one prime-size byte array.
	 */
	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
	unsigned char *blob = fmalloc(giantBytes);
	if(blob == NULL) {
		return FR_Memory;
	}
	serializeGiant(pkinst->privGiant, blob, giantBytes);
	*keyBlob = blob;
	*keyBlobLen = giantBytes;
	return FR_Success;
}
/*
 * Obtain a malloc'd memory chunk init'd with specified giant's data.
 * Resulting bytes are portable. Size of malloc'd memory is always zero
 * mod GIANT_BYTES_PER_DIGIT.
 *
 * Calling this function for a giant obtained by giant_with_data() yields
 * the original data, with extra byte(s) of leading zeros if the original
 * was not zero mod GIANT_BYTES_PER_DIGIT.
 */
unsigned char *mem_from_giant(giant g,
	unsigned *memLen)		/* RETURNED size of malloc'd region */
{
	unsigned char *cp;
	unsigned numDigits = (g->sign < 0) ? -g->sign : g->sign;

	*memLen = numDigits * GIANT_BYTES_PER_DIGIT;
	cp = (unsigned char*) fmalloc(*memLen);
	serializeGiant(g, cp, *memLen);
	return cp;
}
/*
 * ANSI X9.62/Certicom key support.
 * Public key is 04 || x || y
 * Private key is privData per Certicom SEC1 C.4.
 */
feeReturn feeCreateECDSAPubBlob(feePubKey pubKey,
	unsigned char **keyBlob,
	unsigned *keyBlobLen)
{
	pubKeyInst *pkinst = (pubKeyInst *)pubKey;
	if(pkinst == NULL) {
		return FR_BadPubKey;
	}
	
	unsigned giantBytes = (pkinst->cp->q + 7) / 8;
	unsigned blobSize = 1 + (2 * giantBytes);
	unsigned char *blob = fmalloc(blobSize);
	if(blob == NULL) {
		return FR_Memory;
	}
	*blob = 0x04;
	serializeGiant(pkinst->plus->x, blob+1, giantBytes);
	serializeGiant(pkinst->plus->y, blob+1+giantBytes, giantBytes);
	*keyBlob = blob;
	*keyBlobLen = blobSize;
	return FR_Success;
}
Example #4
0
static OSStatus sslGiantToBuffer(
	SSLContext			*ctx,			// Currently unused.
	giant g,
	SSLBuffer *buffer)
{
	gi_uint8 *chars;
	gi_uint16 ioLen;
	gi_uint16 zeroCount;
	GIReturn giReturn;
	OSStatus status;

	ioLen = serializeGiantBytes(g);
	status = SSLAllocBuffer(buffer, ioLen, ctx);
	if (status)
		return status;
	chars = buffer->data;

	/* Serialize the giant g into chars. */
	giReturn = serializeGiant(g, chars, &ioLen);
	if(giReturn) {
		SSLFreeBuffer(buffer, ctx);
		return giReturnToSSL(giReturn);
	}

	/* Trim off leading zeroes (but leave one zero if that's all there is). */
	for (zeroCount = 0; zeroCount < (ioLen - 1); ++zeroCount)
		if (chars[zeroCount])
			break;

	if (zeroCount > 0) {
		buffer->length = ioLen - zeroCount;
		memmove(chars, chars + zeroCount, buffer->length);
	}

	return status;
}
Example #5
0
/*
 * Decrypt (exactly) a block of data. Caller malloc's plainText. Always
 * generates feeFEEDExpPlainBlockSize of plaintext, unless finalBlock is
 * non-zero (in which case feeFEEDExpPlainBlockSize or less bytes of
 * plainText are generated).
 */
feeReturn feeFEEDExpDecryptBlock(feeFEEDExp feed,
	const unsigned char *cipherText,
	unsigned cipherTextLen,
	unsigned char *plainText,
	unsigned *plainTextLen,			// RETURNED
	int finalBlock)
{
	feedInst 	*finst = (feedInst *) feed;
	char 		g;
	int 		s;
	feeReturn	frtn = FR_Success;
	curveParams	*cp = finst->cp;
	
	if(finst->gPriv == NULL) {
		/*
		 * Can't decrypt without private data
		 */
		return FR_BadPubKey;
	}

	/*
	 * grab xm, xc, and g from cipherText
	 */
	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	// FEED_DEBUG

	if((g & CLUE_ELL_ADD_SIGN) == CLUE_ELL_ADD_SIGN_PLUS) {
		s = SIGN_PLUS;
	}
	else {
		s = SIGN_MINUS;
	}

	/*
	 * xc = r(P1?)
	 * xc := r(P1?)(pri) = xq
	 * xp = data + r(priB+) +/- pri(rB?)
	 */
	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);

	/*
	 * plaintext in xp
	 */
	#if	FEED_DEBUG
	printf("  xp : "); PRINT_GIANT(finst->xp);
	#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 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;
}
Example #6
0
/*
 * Encrypt a block or less of data. Caller malloc's cipherText.
 */
feeReturn feeFEEDExpEncryptBlock(feeFEEDExp feed,
	const unsigned char *plainText,
	unsigned plainTextLen,
	unsigned char *cipherText,
	unsigned *cipherTextLen,		// RETURNED
	int finalBlock)
{
	feedInst 		*finst = (feedInst *) feed;
	int 			index;				/* which curve (+/- 1) */
	char 			g = 0;				/* parity, which_curve bits in ciphertext */
	key 			B;
	unsigned char	*ptext;				/* for final block */
	unsigned		ctextLen;
	feeReturn		frtn = FR_Success;
	giant			x1;
	unsigned		randLen;
	curveParams		*cp = finst->cp;
    randLen = cp->minBytes+8; // +8bytes (64bits)  to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits"

	if(plainTextLen > finst->plainBlockSize) {
		return FR_IllegalArg;
	}
	else if ((plainTextLen < finst->plainBlockSize) && !finalBlock) {
		return FR_IllegalArg;
	}

	/*
	 * Init only on first encrypt
	 */
	if((finst->randFcn == NULL) && (finst->rand == NULL)) {
		finst->rand = feeRandAlloc();
	}
	if(finst->randData == NULL) {
		finst->randData = (unsigned char*) fmalloc(randLen);
	}
	
	/*
	 * plaintext as giant xp
	 */
	if(finalBlock) {
		ptext = (unsigned char*) fmalloc(finst->plainBlockSize);
		bzero(ptext, finst->plainBlockSize);
		if(plainTextLen) {
			/*
			 * 0 for empty block with resid length 0
			 */
			bcopy(plainText, ptext, plainTextLen);
		}
		if(plainTextLen < finst->plainBlockSize) {
		    if(plainTextLen == 0) {
		    	/*
				 * Special case - can't actually write zero here;
				 * it screws up deserializing the giant during
				 * decrypt
				 */
		        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
		}
		/*
		 * else handle evenly aligned case below...
		 */
		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	// FEED_DEBUG

	/*
	 * pick curve B? that data lies upon
	 */
	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

	/*
	 * random number as giant xaux
	 */
	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	// FEE_DEBUG
	/*
	 * Justify random # to be in [2, minimumX1Order].
	 */
	lesserX1OrderJustify(finst->xaux, cp);
	#if		FEED_DEBUG
	printf(" xaux: "); PRINT_GIANT(finst->xaux);
	#endif	// FEED_DEBUG

	gtog(B->x, finst->xq);				// xq = pubB?
    elliptic_simple(finst->xq, finst->xaux, cp);
										// xq = r(pubB?)
	#if		FEED_DEBUG
	printf(" r(pubB?): "); PRINT_GIANT(finst->xq);
	#endif
	elliptic_add(finst->xp, finst->xq, finst->xm, cp, SIGN_PLUS);
										// xm = data + r(pubB?)
	gtog(x1, finst->xc);
    elliptic_simple(finst->xc, finst->xaux, cp);
										// xc = r(P1?)
	elliptic_add(finst->xm, finst->xq, finst->xaux, cp, SIGN_PLUS);
										// xaux = xm + xq (for curve +1)
										//      = (data + r(pubB?)) + r(pubB?)
	if(gcompg(finst->xaux, finst->xp) == 0) {
		g |= CLUE_ELL_ADD_SIGN_PLUS;
	}
	else {
		g |= CLUE_ELL_ADD_SIGN_MINUS;
		#if	FEED_DEBUG
		/* this better be true.... */
		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
	}									// g = (xaux == data) ? add : subtract

	/*
	 * Ciphertext = (xm, xc, g)
	 */
	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	// 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

		#if FEED_DEBUG
		printf("encrypt: one more empty block\n");
		#endif
		frtn = feeFEEDExpEncryptBlock(feed,
			NULL,				// plainText not used
			0,				// resid
			cipherText,			// append...
			&moreCipher,
			1);
		if(frtn == FR_Success) {
			ctextLen += moreCipher;
		}
	}

	*cipherTextLen = ctextLen;
	return frtn;
}
/* 
 * Diffie-Hellman. Public key is specified either as a feePubKey or 
 * a ANSI X9.62 format public key string (0x04 | x | y). In either case
 * the caller must ensure that the two keys are on the same curve. 
 * Output data is fmalloc'd here; caller must free. Output data is 
 * exactly the size of the curve's modulus in bytes. 
 */
feeReturn feePubKeyECDH(
	feePubKey privKey,
	/* one of the following two is non-NULL */
	feePubKey pubKey,
	const unsigned char *pubKeyStr,
	unsigned pubKeyStrLen,
	/* output fmallocd and RETURNED here */
	unsigned char **output,
	unsigned *outputLen)
{
	feePubKey theirPub = pubKey;
	feeReturn frtn = FR_Success;
	pubKeyInst *privInst = (pubKeyInst *) privKey;
	
	if(privInst->privGiant == NULL) {
		dbgLog(("feePubKeyECDH: privKey not a private key\n"));
		return FR_IncompatibleKey;
	}
	
	if(theirPub == NULL) {
		if(pubKeyStr == NULL) {
			return FR_IllegalArg;
		}
		
		/* Cook up a public key with the same curveParams as the private key */
		feeDepth depth;
		frtn = curveParamsDepth(privInst->cp, &depth);
		if(frtn) {
			return frtn;
		}
		theirPub = feePubKeyAlloc();
		if(theirPub == NULL) {
			return FR_Memory;
		}
		frtn = feePubKeyInitFromECDSAPubBlob(theirPub, pubKeyStr, pubKeyStrLen, depth);
		if(frtn) {
			goto errOut;
		}
	}
	
	pubKeyInst *pubInst = (pubKeyInst *) theirPub;
	
	giant outputGiant = make_pad(privInst->privGiant, pubInst->plus);
	if(outputGiant == NULL) {
		dbgLog(("feePubKeyECDH: make_pad error\n"));
		frtn = FR_Internal;
	}
	else {
		*outputLen = (privInst->cp->q + 7) / 8;
		*output = (unsigned char *)fmalloc(*outputLen);
		if(*output == NULL) {
			frtn = FR_Memory;
			goto errOut;
		}
		serializeGiant(outputGiant, *output, *outputLen);
		freeGiant(outputGiant);
	}
errOut:
	if((pubKey == NULL) && (theirPub != NULL)) {
		feePubKeyFree(theirPub);
	}
	return frtn;
}
Example #8
0
/*
 * 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;
}
Example #9
0
/*
 * 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;
}