feeFEEDExp.c   [plain text]


/* Copyright (c) 1998 Apple Computer, 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 COMPUTER, INC. AND THE
 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
 * EXPOSE YOU TO LIABILITY.
 ***************************************************************************
 *
 * FeeFEEDExp.c - generic FEED encryption object, 2:1 expansion
 *
 * Revision History
 * ----------------
 * 10/06/98		ap
 *	Changed to compile with C++.
 * 20 Jan 1998	Doug Mitchell at Apple
 * 	Mods for primeType == PT_GENERAL case.
 * 12 Jun 1997	Doug Mitchell at Apple
 *	Was curveOrderJustify(), is lesserX1OrderJustify()
 * 03 Mar 1997	Doug Mitchell at Apple
 *	Trimmed plainBlockSize by one byte if q mod 8 = 0
 * 03 Feb 97	Doug Mitchell at NeXT
 *	Renamed to feeFEEDExp.c
 *	Justified random xaux to [2, minimumX1Order]
 *	Added feeFEEDExpCipherTextSize()
 * 15 Jan 97	Doug Mitchell at NeXT
 *	Cleaned up which_curve/index code to use CURVE_MINUS/CURVE_PLUS
 * 28 Aug 96	Doug Mitchell at NeXT
 *	Created from Blaine Garst's NSFEECryptor.m.
 */

#include "ckconfig.h"

#if	CRYPTKIT_ASYMMETRIC_ENABLE

#include "feeTypes.h"
#include "feeFEEDExp.h"
#include "feePublicKey.h"
#include "feePublicKeyPrivate.h"
#include "elliptic.h"
#include "falloc.h"
#include "feeRandom.h"
#include "ckutilities.h"
#include "feeFunctions.h"
#include "platform.h"
#include "feeDebug.h"
#include <stdlib.h>

#define	FEED_DEBUG				0

#define PRINT_GIANT(g)	printGiant(g)

/*
 * Format of clue byte. Currently just one bit. 
 */
#define CLUE_ELL_ADD_SIGN		0x01
#define CLUE_ELL_ADD_SIGN_PLUS	0x01
#define CLUE_ELL_ADD_SIGN_MINUS	0x00

/*
 * Private data.
 */
typedef struct {
	key			plus;
	key			minus;
	unsigned	plainBlockSize;	/* plaintext block size */
	unsigned	cipherBlockSize;/* ciphertext block size */
	curveParams	*cp;
	giant		gPriv;		/* private data, only for decrypt */
	/* one of the follow two is valid for encrypt */
	feeRand		rand;		/* only created for encrypt */
	feeRandFcn	randFcn;
	void		*randRef;
	
	/*
	 * temporary variables used for encrypt/decrypt. The values in these
	 * is 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		xc;		/* clue = r(P1?) */
	giant		xq;		/* r(pubB?) or priB?(xc) */
	giant		xm;		/* ciphertext */
	giant		xaux;		/* scratch */
	unsigned char	*randData;	/* only created for encrypt */
} feedInst;

/*
 * "zero residue" indicator.
 */
#define RESID_ZERO	0xff

/*
 * Alloc and init a feeFEEDExp object associated with specified feePubKey.
 */
feeFEEDExp feeFEEDExpNewWithPubKey(
	feePubKey pubKey,
	feeRandFcn randFcn,		// optional 
	void *randRef)
{
	feedInst 		*finst = (feedInst *) fmalloc(sizeof(feedInst));
	giant 			privGiant;

	finst->cp = curveParamsCopy(feePubKeyCurveParams(pubKey));
	finst->plus = new_public_with_key(feePubKeyPlusCurve(pubKey),
		finst->cp);
	finst->minus = new_public_with_key(feePubKeyMinusCurve(pubKey),
		finst->cp);

	/*
	 * These might yield NULL data; we can only encrypt in that case.
	 */
	privGiant = feePubKeyPrivData(pubKey);
	if(privGiant) {
		finst->gPriv = newGiant(finst->cp->maxDigits);
		gtog(privGiant, finst->gPriv);
	}
	else {
		finst->gPriv = NULL;
	}

	/*
	 * Conservative, rounding down, on plaintext blocks since we don't
	 * want to split bytes.
	 */
	if(finst->cp->primeType == FPT_General) {
	    unsigned blen = bitlen(finst->cp->basePrime);

	    finst->plainBlockSize = blen / 8;
	    if((blen % 8) == 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--;
	    }
	}

	/*
	 * One block of ciphertext - two giants (with implied sign) and a
	 * parity byte
	 */
	finst->cipherBlockSize = (2 * finst->cp->minBytes) + 1;

	finst->xp = newGiant(finst->cp->maxDigits);
	finst->xc = newGiant(finst->cp->maxDigits);
	finst->xq = newGiant(finst->cp->maxDigits);
	finst->xm = newGiant(finst->cp->maxDigits);
	finst->xaux = newGiant(finst->cp->maxDigits);
	finst->rand = NULL;
	finst->randData = NULL;
	finst->randFcn = randFcn;
	finst->randRef = randRef;
	return finst;
}

void feeFEEDExpFree(feeFEEDExp feed)
{
	feedInst *finst = (feedInst *) feed;

	free_key(finst->plus);
	free_key(finst->minus);
	freeGiant(finst->xc);
	clearGiant(finst->xp); freeGiant(finst->xp);
	clearGiant(finst->xq); freeGiant(finst->xq);
	freeGiant(finst->xm);
	clearGiant(finst->xaux); freeGiant(finst->xaux);
	if(finst->gPriv) {
		clearGiant(finst->gPriv);
		freeGiant(finst->gPriv);
	}
	if(finst->rand) {
		feeRandFree(finst->rand);
	}
	if(finst->randData) {
		ffree(finst->randData);
	}
	if(finst->cp) {
		freeCurveParams(finst->cp);
	}
	ffree(finst);
}

unsigned feeFEEDExpPlainBlockSize(feeFEEDExp feed)
{
	feedInst *finst = (feedInst *) feed;

	return finst->plainBlockSize;
}

unsigned feeFEEDExpCipherBlockSize(feeFEEDExp feed)
{
	feedInst *finst = (feedInst *) feed;

	return finst->cipherBlockSize;
}

unsigned feeFEEDExpCipherBufSize(feeFEEDExp feed)
{
	feedInst *finst = (feedInst *) feed;

	return 2 * finst->cipherBlockSize;
}

/*
 * Return the size of ciphertext to hold specified size of plaintext.
 */
unsigned feeFEEDExpCipherTextSize(feeFEEDExp feed, unsigned plainTextSize)
{
	/*
	 * Normal case is one block of ciphertext for each block of
	 * plaintext. Add one cipherBlock if
	 * plainTextSize % plainBlockSize == 0.
	 */
	feedInst *finst = (feedInst *) feed;
	unsigned blocks = (plainTextSize + finst->plainBlockSize - 1) /
		finst->plainBlockSize;

	if((plainTextSize % finst->plainBlockSize) == 0) {
		blocks++;
	}
	return blocks * finst->cipherBlockSize;
}

/*
 * Return the size of plaintext to hold specified size of decrypted ciphertext.
 */
unsigned feeFEEDExpPlainTextSize(feeFEEDExp feed, unsigned cipherTextSize)
{
	feedInst *finst = (feedInst *) feed;
	unsigned blocks = (cipherTextSize + finst->cipherBlockSize - 1) /
		finst->cipherBlockSize;

	return blocks * finst->plainBlockSize;
}

/*
 * 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;
	
	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(finst->cp->minBytes);
	}
	
	/*
	 * 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
	 */
	randLen = cp->minBytes;
	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;
}

/*
 * 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;
}

/*
 * Convenience routines to encrypt & decrypt multi-block data.
 */
feeReturn feeFEEDExpEncrypt(feeFEEDExp 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;
	unsigned char		*ctextPtr;
	unsigned 		ctextLenTotal;		// running total
	feeReturn		frtn;
	int			finalBlock;
	unsigned		numBlocks;
	unsigned		plainBlockSize;

	if(plainTextLen == 0) {
		dbgLog(("feeFEEDExpDecrypt: NULL plainText\n"));
		return FR_IllegalArg;
	}

	ptext = plainText;
	ptextLen = plainTextLen;
	ctext = (unsigned char*) fmalloc(feeFEEDExpCipherBufSize(feed));
	plainBlockSize = feeFEEDExpPlainBlockSize(feed);
	numBlocks = (plainTextLen + plainBlockSize - 1)/plainBlockSize;
	ctextResultLen = (numBlocks + 1) * feeFEEDExpCipherBlockSize(feed);
	ctextResult = (unsigned char*) fmalloc(ctextResultLen);
	ctextPtr = ctextResult;
	ctextLenTotal = 0;

	while(1) {
		if(ptextLen <= plainBlockSize) {
			finalBlock = 1;
			thisPtextLen = ptextLen;
		}
		else {
			finalBlock = 0;
			thisPtextLen = plainBlockSize;
		}
		frtn = feeFEEDExpEncryptBlock(feed,
			ptext,
			thisPtextLen,
			ctext,
			&ctextLen,
			finalBlock);
		if(frtn) {
			dbgLog(("feeFEEDExpEncrypt: encrypt error: %s\n",
				feeReturnString(frtn)));
			break;
		}
		if(ctextLen == 0) {
			dbgLog(("feeFEEDExpEncrypt: null ciphertext\n"));
			frtn = FR_Internal;
			break;
		}
		bcopy(ctext, ctextPtr, ctextLen);
		ctextLenTotal += ctextLen;
		if(ctextLenTotal > ctextResultLen) {
			dbgLog(("feeFEEDExpEncrypt: ciphertext overflow\n"));
			frtn = FR_Internal;
			break;
		}
		if(finalBlock) {
			break;
		}
		ctextPtr += ctextLen;
		ptext += thisPtextLen;
		ptextLen -= thisPtextLen;
	}

	ffree(ctext);
	if(frtn) {
		ffree(ctextResult);
		*cipherText = NULL;
		*cipherTextLen = 0;
	}
	else {
		*cipherText = ctextResult;
		*cipherTextLen = ctextLenTotal;
		#if	FEE_DEBUG
		if(feeFEEDExpCipherTextSize(feed, plainTextLen) !=
			    ctextLenTotal) {
		    printf("feeFEEDExpEncrypt: feeFEEDCipherTextSize "
		    	"error!\n");
		    printf("ptext %d  exp ctext %d  actual ctext %d\n",
		    	plainTextLen,
			feeFEEDExpCipherTextSize(feed, plainTextLen),
			ctextLenTotal);
		}
		#endif	// FEE_DEBUG
	}
	return frtn;

}

feeReturn feeFEEDExpDecrypt(feeFEEDExp 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 =
					feeFEEDExpPlainBlockSize(feed);
	unsigned		cipherBlockSize =
					feeFEEDExpCipherBlockSize(feed);

	if(cipherTextLen % cipherBlockSize) {
		dbgLog(("feeFEEDExpDecrypt: unaligned cipherText\n"));
		return FR_BadCipherText;
	}
	if(cipherTextLen == 0) {
		dbgLog(("feeFEEDExpDecrypt: NULL cipherText\n"));
		return FR_BadCipherText;
	}

	ptext = (unsigned char*) fmalloc(plainBlockSize);
	ctext = cipherText;
	ctextLen = cipherTextLen;
	numBlocks = cipherTextLen / cipherBlockSize;
	ptextResult = (unsigned char*) fmalloc(plainBlockSize * numBlocks);
	ptextPtr = ptextResult;
	ptextLenTotal = 0;

	while(ctextLen) {
		if(ctextLen == cipherBlockSize) {
		    finalBlock = 1;
		}
		else {
		    finalBlock = 0;
		}
		frtn = feeFEEDExpDecryptBlock(feed,
			ctext,
			cipherBlockSize,
			ptext,
			&ptextLen,
			finalBlock);
		if(frtn) {
			dbgLog(("feeFEEDExpDecryptBlock: %s\n",
				feeReturnString(frtn)));
			break;
		}
		if(ptextLen == 0) {
			/*
			 * Normal termination case for
			 * plainTextLen % plainBlockSize == 0
			 */
			if(!finalBlock) {
			    dbgLog(("feeFEEDExpDecrypt: decrypt sync"
			    	" error!\n"));
			    frtn = FR_BadCipherText;
			}
			break;
		}
		else if(ptextLen > plainBlockSize) {
			dbgLog(("feeFEEDExpDecrypt: ptext overflow!\n"));
			frtn = FR_Internal;
			break;
		}
		else {
			bcopy(ptext, ptextPtr, ptextLen);
			ptextPtr += ptextLen;
			ptextLenTotal += ptextLen;
		}
		ctext += cipherBlockSize;
		ctextLen -= cipherBlockSize;
	}

	ffree(ptext);
	if(frtn) {
		ffree(ptextResult);
		*plainText = NULL;
		*plainTextLen = 0;
	}
	else {
		*plainText = ptextResult;
		*plainTextLen = ptextLenTotal;
	}
	return frtn;

}

#endif	/* CRYPTKIT_ASYMMETRIC_ENABLE */