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