1/*
2 * Copyright (c) 1997,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include "comcryption.h"
29#include "comDebug.h"
30#include "comcryptPriv.h"
31
32#if		COM_PROFILE
33
34unsigned comProfEnable;
35comprof_t cmcTotal;
36comprof_t cmcQueSearch;
37comprof_t cmcQueMatchMove;
38comprof_t cmcQueMissMove;
39comprof_t cmcLevel2;
40comprof_t cmcPerWordOhead;
41
42#endif	/*COM_PROFILE*/
43
44void comMallocRegister(comMallocExternFcn *mallocExtern,
45	comFreeExternFcn *freeExtern)
46{
47	comMallocExt = mallocExtern;
48	comFreeExt = freeExtern;
49}
50
51/*
52 * Call once at startup. The resulting comcryptObj can be reused multiple
53 * times.
54 */
55comcryptObj comcryptAlloc(void)
56{
57	comcryptPriv	*cpriv = (comcryptPriv *) ascMalloc(sizeof(comcryptPriv));
58
59	if(cpriv == NULL) {
60		return NULL;
61	}
62	memset(cpriv, 0, sizeof(comcryptPriv));
63
64#if		COMCRYPT_EXPORT_ONLY
65	cpriv->key = (unsigned char *)ascMalloc(EXPORT_KEY_SIZE);
66#else	/*COMCRYPT_EXPORT_ONLY*/
67	cpriv->key = (unsigned char *)ascMalloc(COMCRYPT_MAX_KEYLENGTH);
68#endif	/*COMCRYPT_EXPORT_ONLY*/
69
70	if(cpriv->key == NULL) {
71		return NULL;
72	}
73	cpriv->map 			  = (unsigned char *)ascMalloc(256);
74	cpriv->invmap 		  = (unsigned char *)ascMalloc(256);
75	if((cpriv->map == NULL) || (cpriv->invmap == NULL)) {
76		return NULL;
77	}
78	mallocCodeBufs(&cpriv->cbuf);
79	if((cpriv->cbuf.codeBuf == NULL) ||
80	   (cpriv->cbuf.level2Buf == NULL)) {
81	 	return NULL;
82	}
83	#if		QUEUE_LOOKAHEAD
84	if(cpriv->cbuf.lookAhead == NULL) {
85	 	return NULL;
86	}
87	#endif
88
89	/*
90	 * Hard coded limit of two levels of comcryption
91	 */
92	cpriv->cbuf.nextBuf = (comcryptBuf *)ascMalloc(sizeof(comcryptBuf));
93	if(cpriv->cbuf.nextBuf == NULL) {
94		return NULL;
95	}
96	mallocCodeBufs(cpriv->cbuf.nextBuf);
97	if((cpriv->cbuf.nextBuf->codeBuf == NULL) ||
98	   (cpriv->cbuf.nextBuf->level2Buf == NULL)) {
99	 	return NULL;
100	}
101	#if		QUEUE_LOOKAHEAD
102	if(cpriv->cbuf.nextBuf->lookAhead == NULL) {
103	 	return NULL;
104	}
105	#endif
106
107	cpriv->cbuf.nextBuf->nextBuf = NULL;
108	return cpriv;
109}
110
111/*
112 * Call this before starting every stream process
113 */
114comcryptReturn comcryptInit(
115	comcryptObj 		cobj,
116    const unsigned char *key,
117    unsigned            keyLen,
118    comcryptOptimize    optimize)			// CCO_SIZE, etc.
119{
120	comcryptPriv	*cpriv = (comcryptPriv *)cobj;
121	unsigned		maxKeySize;
122
123#if		COMCRYPT_EXPORT_ONLY
124	/*
125	 * FIXME - NSA might not be satisfied with this, may have to enforce
126	 * elsewhere
127	 */
128	maxKeySize = EXPORT_KEY_SIZE;
129#else	/*COMCRYPT_EXPORT_ONLY*/
130	maxKeySize = COMCRYPT_MAX_KEYLENGTH;
131#endif	/*COMCRYPT_EXPORT_ONLY*/
132
133	if(keyLen > maxKeySize) {
134		keyLen = maxKeySize;
135	}
136	memmove(cpriv->key, key, keyLen);
137	cpriv->keybytes = keyLen;
138	cpriv->cbuf.codeBufLength = 0;
139	cpriv->cbuf.nextBuf->codeBufLength = 0;
140	cpriv->version = 0;
141	cpriv->versionBytes = 0;
142	cpriv->spareBytes = 0;
143	cpriv->optimize = optimize;
144
145	/*
146	 * Derive feature enable bits from optimize arg. This is highly likely
147	 * to change....
148	 */
149	cpriv->level2enable = 1;
150	cpriv->sigSeqEnable = 1;
151	switch(optimize) {
152	    case CCO_TIME:
153			cpriv->level2enable = 0;
154			break;
155		case CCO_TIME_SIZE:
156			cpriv->sigSeqEnable = 0;
157			break;
158		default:
159			break;
160	}
161#if		QUEUE_LOOKAHEAD
162	cpriv->laEnable = 1;
163#else	/* QUEUE_LOOKAHEAD */
164	cpriv->laEnable = 0;
165#endif	/* QUEUE_LOOKAHEAD */
166
167	/*
168	 * init queue and maps
169	 */
170	initCodeBufs(&cpriv->cbuf, key, keyLen, cpriv->laEnable,
171		cpriv->sigSeqEnable);
172	initCodeBufs(cpriv->cbuf.nextBuf, key, keyLen, cpriv->laEnable,
173		cpriv->sigSeqEnable);
174	key_perm(key, keyLen, cpriv->map, cpriv->invmap);
175	return CCR_SUCCESS;
176}
177
178/*
179 * Free a comcryptObj object obtained via comcryptAlloc()
180 */
181void comcryptObjFree(comcryptObj cobj)
182{
183	comcryptPriv *cpriv = (comcryptPriv *)cobj;
184
185	if(cpriv->key != NULL) {
186		ascFree(cpriv->key);
187	}
188	if(cpriv->map != NULL) {
189		ascFree(cpriv->map);
190	}
191	if(cpriv->invmap != NULL) {
192		ascFree(cpriv->invmap);
193	}
194	freeCodeBufs(&cpriv->cbuf);
195	ascFree(cpriv);
196}
197
198/*
199 * Return the maximum input buffer size allowed for for specified
200 * output buffer size. Note that for both comcrypt and decomcrypt,
201 * to cover the worst case, the output buffer always has to be
202 * larger than the input buffer.
203 */
204unsigned comcryptMaxInBufSize(comcryptObj cobj,
205    unsigned outBufSize,
206    comcryptOp op)
207{
208	unsigned fullBlocks;
209	unsigned minCblockSize;
210	unsigned resid;
211	unsigned rtn;
212	unsigned tokenBytes;
213	comcryptPriv *cpriv = (comcryptPriv *)cobj;
214	unsigned ptextFromCodeBuf;
215
216	switch(op) {
217	    case CCOP_COMCRYPT:
218			/*
219			 * Worst case: no compression. Also, establish a minimum
220			 * ciphertext size to accomodate header and one block.
221			 */
222			minCblockSize = MIN_CBLOCK_SIZE;
223			if(cpriv->versionBytes == 0) {
224				minCblockSize += CTEXT_HDR_SIZE;
225			}
226			if(outBufSize < (minCblockSize)) {
227				return 0;
228			}
229			if(cpriv->versionBytes == 0) {
230				outBufSize -= CTEXT_HDR_SIZE;
231			}
232			fullBlocks = outBufSize / MAX_CBLOCK_SIZE;
233			rtn = (fullBlocks * CC_BLOCK_SIZE);		// bytes of ptext
234
235			/*
236			 * code must be even aligned, then chop off one for odd ptext
237			 */
238			rtn &= 0xfffffffe;
239			rtn--;
240			if(rtn <= 0) {
241				return 0;
242			}
243			resid = outBufSize % MAX_CBLOCK_SIZE;
244			if(resid) {
245				rtn += resid;
246
247				/*
248				 * Account for resid block overhead
249				 */
250				if(rtn < MIN_CBLOCK_SIZE) {
251					return 0;
252				}
253				rtn -= MIN_CBLOCK_SIZE;
254
255				tokenBytes = TOKEN_BYTES_FROM_PTEXT(resid);
256				if(rtn <= tokenBytes) {
257					return 0;
258				}
259				rtn -= tokenBytes;
260			}
261			if(rtn > INBUF_TRUNC_THRESH) {
262				/*
263				 * Truncate to even block size to minimize partial cipherblocks
264				 */
265				rtn &= ~(CC_BLOCK_SIZE - 1);
266			}
267			return rtn;
268
269		case CCOP_DECOMCRYPT:
270			/*
271			 * Worst case - 4:1 compression and an almost full block in
272			 * codeBuf. Note 4:1 is a super-conservative, easy arithmetic
273			 * version of (9/16) squared...
274			 */
275			ptextFromCodeBuf = cpriv->cbuf.codeBufLength * 4;
276			if(outBufSize < ptextFromCodeBuf) {
277				/* decrypting codeBuf might overflow output (plaintext)
278				 * buffer - won't be able to move anything */
279				rtn = 0;
280			}
281			else {
282				/* can decrypt (this much plainText - ptextFromCodeBuf) / 4 */
283				rtn = (outBufSize - ptextFromCodeBuf) / 4;
284			}
285
286			/* may be able to handle a bit extra for initial decrypt... */
287			if(cpriv->versionBytes < VERSION_BYTES) {
288				rtn += (VERSION_BYTES - cpriv->versionBytes);
289			}
290			if(cpriv->spareBytes < SPARE_BYTES) {
291				rtn += (SPARE_BYTES - cpriv->spareBytes);
292			}
293			return rtn;
294
295		default:
296			ddprintf(("bogus op (%d) in comcryptMaxInBufSize()\n", op));
297			return 0;
298	}
299}
300
301/*
302 * Return the maximum output buffer size for specified input buffer size.
303 * Output buffer size will always be larger than input buffer size.
304 */
305unsigned comcryptMaxOutBufSize(comcryptObj cobj,
306    unsigned inBufSize,
307    comcryptOp op,
308	char final)
309{
310	unsigned fullBlocks;
311	unsigned resid;
312	unsigned rtn;
313	comcryptPriv *cpriv = (comcryptPriv *)cobj;
314
315	switch(op) {
316	    case CCOP_COMCRYPT:
317			fullBlocks = inBufSize / CC_BLOCK_SIZE;
318			rtn = fullBlocks * MAX_CBLOCK_SIZE;
319			resid = inBufSize % CC_BLOCK_SIZE;
320			if(resid != 0) {
321				/*
322				 * partial block
323				 */
324				unsigned tokenBytes = TOKEN_BYTES_FROM_PTEXT(resid);
325
326				rtn += MIN_CBLOCK_SIZE;
327				rtn += tokenBytes;
328				rtn += resid;			// no compression
329				if(resid & 1) {
330					rtn++;				// oddByte uses extra
331				}
332			}
333			if((cpriv == NULL) || 		// i.e., we're being called from mallocCodeBufs
334			   (cpriv->versionBytes == 0)) {
335				rtn += CTEXT_HDR_SIZE;	// first of a stream
336			}
337			return rtn;
338
339		case CCOP_DECOMCRYPT:
340			/*
341			 * Here assume max compression, including resid block in codeBuf
342			 */
343			inBufSize += cpriv->cbuf.codeBufLength;
344			if(inBufSize) {
345				/* may be able to handle a bit extra for initial decrypt... */
346				unsigned delta;
347				if(cpriv->versionBytes < VERSION_BYTES) {
348					delta = VERSION_BYTES - cpriv->versionBytes;
349					if(inBufSize > delta) {
350						inBufSize -= delta;
351					}
352					else {
353						inBufSize = 0;
354					}
355				}
356				if(cpriv->spareBytes < SPARE_BYTES) {
357					delta = SPARE_BYTES - cpriv->spareBytes;
358					if(inBufSize > delta) {
359						inBufSize -= delta;
360					}
361					else {
362						inBufSize = 0;
363					}
364				}
365			}
366			rtn = 4 * inBufSize;
367			return rtn;
368
369		default:
370			ddprintf(("bogus op (%d) in comcryptMaxOutBufSize()\n", op));
371			return 0;
372	}
373}
374
375/*
376 * Threshold for using memmove() rather than hard-coded loop for
377 * moving queue segment. This was derived empirically on a Pentium;
378 * we should do similar measurements on PPC.
379 */
380#define	QUEUE_MEMMOVE_THRESH	3
381
382/*
383 * peek at queue[0] before search. This appears to only be a win for
384 * constant plaintext, i.e., the codeword is almost always at queue[0].
385 */
386#define QUEUE_PEEK		0
387
388/*
389 * Comcrypt one block.
390 */
391static comcryptReturn comcryptBlock(
392	comcryptPriv 		*cpriv,
393	comcryptBuf			*cbuf,				// not necessarily cpriv->cbuf
394	const unsigned char	*plainText,
395	unsigned			plainTextLen,
396	unsigned char		*cipherText,
397	unsigned			*cipherTextLen,		// IN/OUT
398	unsigned			recursLevel)
399{
400	unsigned char 	*byteCodePtr;
401	unsigned char	*destByteCodePtr;
402	unsigned char 	*longCodePtr;
403	unsigned char	*startLongCodePtr;
404	unsigned char 	*tokenPtr;
405	unsigned char	*startTokenPtr;
406	unsigned char	*startCtextPtr = cipherText;
407	unsigned 		numTokenBytes;		// in bytes, constant
408	unsigned short 	codeWord;
409	unsigned		oddByte = 0;
410	unsigned		match;
411	unsigned		jmatch=0;
412	unsigned		tokenDex = 0;		// index into array of token bits
413	unsigned		j;
414	unsigned		numLongCodes = 0;
415	unsigned		numByteCodes = 0;
416	unsigned		totalCipherTextLen;
417	unsigned		above;
418	unsigned		jmatchTotal = 0;
419	unsigned		jmatchAvg;
420	comcryptReturn	crtn;
421	unsigned char 	blockDesc = CBD_MAGIC;
422	unsigned		fullBlock = 0;
423	int				len;
424	queueElt		*src;
425	queueElt		*dst;
426	queueElt 		*cbufq = &cbuf->queue[0];
427
428	/*
429	 * 'nibble' is added to 'above' in the call to nextSigWord() for
430	 * additional security.
431	 *
432	 * Normal case : nibble = keynybble()
433	 * last word on odd byte : nibble = nibbleDex
434	 * hit on queue q : nibble = nibbleDex (optimize to avoid keynybble()
435	 *     call)
436	 */
437	unsigned char	nibble;
438
439	COMPROF_LOCALS;
440
441	#if		COM_LA_DEBUG
442	if(testLookAhead(cbuf, 0, 0)) {
443		return CCR_INTERNAL;
444	}
445	#endif
446
447	laprintf(("comcryptBlock recurs level %d\n", recursLevel));
448
449	/*
450	 * Set up ptrs for the three arrays we'll be writing
451	 */
452	tokenPtr = cipherText + CTBO_NUM_TOKENS + 1;
453	if(plainTextLen >= (CC_BLOCK_SIZE - 1)) {
454		/*
455		 * Optimized for full block - no token count in block. Note
456		 * that plainTextLen == (CC_BLOCK_SIZE - 1) is also a full block
457		 * in that it uses up a full block's worth of tokens!
458		 */
459		numTokenBytes = CC_BLOCK_SIZE >> 4;
460		tokenPtr--;
461		blockDesc |= CBD_FULL_BLOCK;
462		fullBlock = 1;
463	}
464	else {
465		numTokenBytes = (plainTextLen + 15) >> 4;
466	}
467	longCodePtr  	  = tokenPtr + numTokenBytes;
468	startLongCodePtr  = longCodePtr;
469	byteCodePtr	   	  = cbuf->codeBuf;
470	startTokenPtr 	  = tokenPtr;
471
472	if((unsigned)(longCodePtr - cipherText) > *cipherTextLen) {
473		ddprintf(("comcryptBlock: short block (1)\n"));
474		return CCR_OUTBUFFER_TOO_SMALL;
475	}
476	memset(tokenPtr, 0, numTokenBytes);
477
478	/*
479	 * Entering time-critical region. This loop executes once for every
480	 * 2 bytes of plaintext. Make every attempt to streamline the code
481	 * here; avoid function calls in favor of macros; etc.
482	 */
483	while(plainTextLen != 0) {
484
485		/*
486		 * assemble a 16-bit word from two bytes if possible
487		 */
488		if(plainTextLen == 1) {
489			/*
490			 * Odd byte case
491			 */
492			codeWord = ((unsigned short)(cpriv->map[*plainText]) << 8) |
493						 cpriv->map[0];	// a bit of obfuscation - mapped zero
494			oddByte = 1;
495			blockDesc |= CBD_ODD;
496			plainTextLen--;
497		}
498		else {
499			codeWord = ((unsigned short)(cpriv->map[*plainText]) << 8) |
500			            (unsigned short)(cpriv->map[plainText[1]]);
501			plainText += 2;
502			plainTextLen -= 2;
503		}
504
505		/*
506		 * Calibrate how much profiling is costing us.
507		 */
508		COMPROF_START;
509		COMPROF_END(cmcPerWordOhead);
510
511		/*
512		 * See if this word is in queue[]. Skip if oddByte; we'll force
513		 * a 16-bit word in that case. Also skip the search if we know
514		 * via lookahead that a search would be fruitless.
515		 */
516		COMPROF_START;		/* cmcQueSearch */
517		match = 0;
518		do {				/* while 0 - for easy breaks w/o goto */
519
520			/*
521			 * First handle some optimizations and special cases
522			 */
523			if(oddByte) {
524				break;			// force longcode
525			}
526
527#if		QUEUE_PEEK
528			if(cbufq[0] == codeWord) {
529				match = 1;
530				jmatch = 0;
531				break;
532
533			}
534#endif	/*QUEUE_PEEK*/
535
536			if(cpriv->laEnable && !inQueue(cbuf, codeWord)) {
537				break;
538			}
539
540			/*
541			 * OK, do the gruntwork search
542			 */
543			for(j=0; j < QLEN; j++) {
544				if(cbufq[j] == codeWord) {
545					match = 1;
546					jmatch = j;
547					break;
548				}
549			}
550
551#if		COM_LA_DEBUG
552			if(cpriv->laEnable && !match) {
553				printf("inQueue, not found in queue!\n");
554				return CCR_INTERNAL;
555			}
556
557			/*
558			 * Search for duplicates.
559			 */
560			if(match) {
561				for(j=jmatch+1; j<QLEN; j++) {
562					if(cbufq[j] == codeWord) {
563						printf("***Huh! Dup queue entry codeWord 0x%x jmatch "
564							"0x%x  2nd j 0x%x\n",
565							codeWord, jmatch, j);
566						return CCR_INTERNAL;
567					}
568				}
569			}
570#endif	/*COM_LA_DEBUG*/
571		} while(0);
572
573		COMPROF_END(cmcQueSearch);
574
575		/*
576		 * Note we measure the overhead on a per-codeword basis. Here,
577		 * we ensure that there is exactly one pair of start/end
578		 * timestamps per queue move per code word.
579		 *
580		 * New 17 Dec 1997 - always calculate keynibble for use in signature
581		 * sequence update
582		 */
583#if		!SKIP_NIBBLE_ON_QUEUE_0
584		nibble = keynybble(cpriv->key, cpriv->keybytes,
585						(cbuf->nybbleDex)++);
586#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
587
588		COMPROF_START;
589		if(match) {
590			/*
591			 * 16-bit symbol is in queue. 8 bits of ciphertext, token bit is 0.
592			 */
593			if(jmatch == 0) {
594				/*
595				 * Optimization: jmatch = 0. Keep state machine in sync,
596				 * but skip queue update.
597				 */
598				above = 0;
599				laprintf(("...queue hit at queue[0]\n"));
600#if		SKIP_NIBBLE_ON_QUEUE_0
601				nibble = (cbuf->nybbleDex)++;
602#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
603			}
604			else {
605#if		SKIP_NIBBLE_ON_QUEUE_0
606				nibble = keynybble(cpriv->key, cpriv->keybytes,
607								(cbuf->nybbleDex)++);
608#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
609
610				above = (cbuf->f1 * jmatch * (16 + nibble)) >> 9;
611
612				/*
613				 * queue[above..(jmatch-1)] move one element towards end
614				 * queue[above] = this codeWord
615				 */
616				laprintf(("...queue hit, moving 0x%x from 0x%x to 0x%x\n",
617					codeWord, jmatch, above));
618
619				len = (int)jmatch - (int)above;
620				if(len > QUEUE_MEMMOVE_THRESH) {
621					src = &cbufq[above];
622					dst = src + 1;
623					len *= sizeof(queueElt);
624					memmove(dst, src, len);
625				}
626				else {
627					for(j = jmatch; j>above; j--) {
628						cbufq[j] = cbufq[j-1];
629					}
630				}
631
632				cbufq[above] = codeWord;
633#if		COM_LA_DEBUG
634				if(testLookAhead(cbuf, above, jmatch)) {
635					return CCR_INTERNAL;
636				}
637#endif	/*COM_LA_DEBUG*/
638			}
639			COMPROF_END(cmcQueMatchMove);
640
641			codeWord = jmatch;
642			incr1byteFrags(recursLevel);
643			jmatchTotal += jmatch;
644		}
645		else if(oddByte == 0) {
646			/*
647			 * 16-bit symbol is not in queue. 16 bits of ciphertext.
648			 * Token bit is 1.
649			 *
650			 * queue[above...QLEN-1] move one element toward end
651			 * queue[QLEN-1] discarded
652			 * queue[above] = new codeword
653			 *
654			 * Note we skip this queue manipulation in the oddbyte case, since
655			 * we don't really know (or care) if the current code word is in
656			 * the queue or not.
657			 */
658#if		SKIP_NIBBLE_ON_QUEUE_0
659			nibble = keynybble(cpriv->key, cpriv->keybytes,
660							(cbuf->nybbleDex)++);
661#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
662
663			above = ABOVE(cbuf->f2) + nibble;
664
665#if		COM_DEBUG
666			if(above > QLEN) {
667				printf("Hey Doug! above %d  QLEN %d\n", above, QLEN);
668				return CCR_INTERNAL;
669			}
670#endif
671
672			laprintf(("...queue miss, adding 0x%x at 0x%x, deleting 0x%x\n",
673				codeWord, above, cbufq[QLEN-1]));
674
675			if(cpriv->laEnable) {
676				markInQueue(cbuf, codeWord, 1);			// new entry
677				markInQueue(cbuf, cbufq[QLEN-1], 0);	// bumped out
678			}
679
680			len = QLEN - 1 - (int)above;
681			if(len > QUEUE_MEMMOVE_THRESH) {
682				src = &cbufq[above];
683				dst = src + 1;
684				len *= sizeof(queueElt);
685				memmove(dst, src, len);
686			}
687			else {
688				for(j=QLEN-1; j > above; j--) {
689					cbufq[j] = cbufq[j-1];
690				}
691			}
692
693			cbufq[above] = codeWord;
694
695#if		COM_LA_DEBUG
696			if(testLookAhead(cbuf, above, 0)) {
697				return CCR_INTERNAL;
698			}
699#endif	/*COM_LA_DEBUG*/
700
701			COMPROF_END(cmcQueMissMove);
702			incr2byteFrags(recursLevel);
703		}
704		else {
705			/*
706			 * Odd byte case, at least gather stats.
707			 */
708			incr2byteFrags(recursLevel);
709
710			/*
711			 * ...and keep this in sync for signature sequence
712			 */
713			above = 0;
714#if		SKIP_NIBBLE_ON_QUEUE_0
715			nibble = (cbuf->nybbleDex)++;
716#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
717		}
718
719		updateToken(tokenPtr, tokenDex, !match);
720		tokenDex++;
721
722		if(match) {
723			*byteCodePtr++ = codeWord & 0xff;
724			numByteCodes++;
725		}
726		else {
727			serializeShort(codeWord, longCodePtr);
728			longCodePtr += 2;
729			numLongCodes++;
730		}
731		if(cpriv->sigSeqEnable) {
732			nextSigWord(cbuf, tokenDex, match, (above + nibble));
733		}
734	}
735
736#if		COM_DEBUG
737	if(numTokenBytes != ((tokenDex + 7) >> 3)) {
738		ddprintf(("comcryptBlock: numTokenBytes (%d), tokenDex (%d)\n",
739			numTokenBytes, tokenDex));
740	}
741#endif	/*COM_DEBUG*/
742
743	/*
744	 * We already wrote tokens and longcode to cipherText; verify we
745	 * didn't overrun
746	 */
747	totalCipherTextLen = (unsigned)(longCodePtr - startCtextPtr);
748	if(*cipherTextLen < totalCipherTextLen) {
749		ddprintf(("comcryptBlock: short block (2)\n"));
750		return CCR_OUTBUFFER_TOO_SMALL;
751	}
752	if(!fullBlock) {
753		cipherText[CTBO_NUM_TOKENS] = tokenDex;
754	}
755	cipherText[CTBO_NUM_LONG_CODES] = numLongCodes;
756
757#if		COM_DEBUG
758	if(tokenDex > MAX_TOKENS) {
759		ddprintf(("comcryptBlock: counter overflow!\n"));
760		return CCR_INTERNAL;
761	}
762	if((numByteCodes + numLongCodes) != tokenDex) {
763		ddprintf(("comcryptBlock: counter mismatch!\n"));
764		return CCR_INTERNAL;
765	}
766#endif	/*COM_DEBUG*/
767
768	/*
769	 * See if doing a second level comcryption makes sense.
770	 */
771	destByteCodePtr = startLongCodePtr + (numLongCodes * 2);
772	if(numByteCodes > 0) {
773		jmatchAvg = jmatchTotal / numByteCodes;
774	}
775	else {
776		jmatchAvg = cbuf->jmatchThresh + 1;
777	}
778	if((recursLevel == 0) &&					// hard coded recursion limit
779	   (cpriv->level2enable) &&					// enabled by caller
780	   (numByteCodes >= cbuf->minByteCode) &&	// meaningful # of bytecodes
781	   (jmatchAvg <= cbuf->jmatchThresh)) {		// reasonable compression
782	   											//   already achieved
783
784		unsigned thisCtext = cbuf->level2BufSize;
785
786		COMPROF_START;
787		crtn = comcryptBlock(cpriv,
788				cbuf->nextBuf,
789				cbuf->codeBuf,
790				numByteCodes,
791				cbuf->level2Buf,
792				&thisCtext,
793				recursLevel + 1);
794		if(crtn) {
795			return crtn;
796		}
797
798		/*
799		 * Write level2Buf to cipherText (as byteCodeArray).
800		 * Size of 2nd level comcrypted byte code follows longcode array,
801		 * then the bytecode itself.
802		 * First bump totalCipherTextLen by the size of the comcrypted array
803		 * plus one (for the size byte itself), and verify no overflow
804		 */
805		totalCipherTextLen += (thisCtext + 1);
806		if(*cipherTextLen < totalCipherTextLen) {
807			ddprintf(("comcryptBlock: short block (3)\n"));
808			return CCR_OUTBUFFER_TOO_SMALL;
809		}
810		*destByteCodePtr++ = thisCtext;
811		COMPROF_END(cmcLevel2);
812		memmove(destByteCodePtr, cbuf->level2Buf, thisCtext);
813		blockDesc |= CBD_DOUBLE;
814
815		l2printf(("***2nd-level comcrypt: numByteCodes %d encrypted "
816			"size %d\n", numByteCodes, thisCtext));
817		incrComStat(level2byteCode, numByteCodes);
818		incrComStat(level2cipherText, thisCtext);
819		incrComStat(level2jmatch, jmatchTotal);
820		incrComStat(level2blocks, 1);
821	}
822	else {
823		/*
824		 * Normal one-level comcryption. Write byteCodes to ciphertext.
825		 * numByteCodes is inferred.
826		 */
827		totalCipherTextLen += numByteCodes;
828		if(*cipherTextLen < totalCipherTextLen) {
829			ddprintf(("comcryptBlock: short block (3)\n"));
830			return CCR_OUTBUFFER_TOO_SMALL;
831		}
832		memmove(destByteCodePtr, cbuf->codeBuf, numByteCodes);
833		blockDesc |= CBD_SINGLE;
834		if(recursLevel == 0) {
835			incrComStat(level1blocks, 1);
836		}
837		/* else this is a 2nd-level, our caller will count */
838
839		/*
840		 * obfuscate via sigArray (only when we're NOT doing 2nd level
841		 *  comcrypt)
842		 */
843		if(cpriv->sigSeqEnable) {
844			sigMunge(cbuf, startTokenPtr, tokenDex,
845				destByteCodePtr, startLongCodePtr);
846
847			/*
848			 * Prime sigArray state machine for next block. Note in the case
849			 * of 2nd level, we skip this step, so the next block starts from
850			 * the same state as this one did.
851			 */
852			cbuf->sigArray[0] = cbuf->sigArray[tokenDex];
853		}
854	}
855	cipherText[CTBO_BLOCK_DESC] = blockDesc;
856	*cipherTextLen = totalCipherTextLen;
857	return CCR_SUCCESS;
858}
859
860/*
861 * Main public encrypt function.
862 */
863comcryptReturn comcryptData(
864	comcryptObj 			cobj,
865	unsigned char 			*plainText,
866	unsigned 				plainTextLen,
867	unsigned char 			*cipherText,		// malloc'd by caller
868	unsigned 				*cipherTextLen,		// IN/OUT
869	comcryptEos 			endOfStream) 		// CCE_END_OF_STREAM, etc.
870{
871	comcryptPriv	*cpriv = (comcryptPriv *)cobj;
872	unsigned		ctextLen = *cipherTextLen;
873	comcryptReturn	crtn;
874	unsigned		thisPtext;
875	unsigned		thisCtext;
876	COMPROF_LOCALS;
877
878	COMPROF_START;
879	incrComStat(plaintextBytes, plainTextLen);
880	if(cpriv->versionBytes == 0) {
881		/*
882		 * First, put header (version, spare) into head of ciphertext.
883		 */
884		if(ctextLen < CTEXT_HDR_SIZE) {
885			ddprintf(("comcryptData: overflow (0)\n"));
886			return CCR_OUTBUFFER_TOO_SMALL;
887		}
888		serializeInt(VERSION_3_Dec_97, cipherText);
889		cipherText += VERSION_BYTES;
890		cpriv->versionBytes = VERSION_BYTES;
891		serializeInt(0, cipherText);				// spares
892		cipherText += SPARE_BYTES;
893		ctextLen   -= CTEXT_HDR_SIZE;
894	}
895
896	/*
897	 * OK, grind it out, one block at a time.
898	 */
899	while (plainTextLen != 0) {
900		thisPtext = CC_BLOCK_SIZE;
901		if(thisPtext > plainTextLen) {
902			thisPtext = plainTextLen;
903		}
904		thisCtext = ctextLen;
905		crtn = comcryptBlock(cpriv,
906			&cpriv->cbuf,
907			plainText,
908			thisPtext,
909			cipherText,
910			&thisCtext,
911			0);			// recurs level
912		if(crtn) {
913			return crtn;
914		}
915		plainText    += thisPtext;
916		plainTextLen -= thisPtext;
917		if(thisCtext > ctextLen) {
918			ddprintf(("comcryptData: undetected ciphertext overlow\n"));
919			return CCR_OUTBUFFER_TOO_SMALL;
920		}
921		cipherText += thisCtext;
922		ctextLen   -= thisCtext;
923	}
924	*cipherTextLen = *cipherTextLen - ctextLen;
925	incrComStat(ciphertextBytes, *cipherTextLen);
926	COMPROF_END(cmcTotal);
927	return CCR_SUCCESS;
928}
929
930/*
931 * Return values from deComcryptBlock().
932 */
933typedef enum {
934	DCB_SUCCESS,			// OK
935	DCB_SHORT,				// incomplete block, try again with more ciphertext
936	DCB_PARSE_ERROR,		// bad block
937	DCB_OUTBUFFER_TOO_SMALL
938} dcbReturn;
939
940/*
941 * Assumes exactly one block of ciphertext, error otherwise.
942 */
943static dcbReturn deComcryptBlock(
944	comcryptPriv 			*cpriv,
945	comcryptBuf				*cbuf,				// not necessarily cpriv->cbuf
946	unsigned char 			*cipherText,
947	unsigned 				cipherTextLen,
948	unsigned char 			*plainText,
949	unsigned	 			*plainTextLen,		// IN/OUT
950	comcryptEos 			endOfStream,		// CCE_END_OF_STREAM, etc.
951	unsigned				*blockSize)			// RETURNED on DCB_SUCCESS
952{
953	unsigned char		*tokenPtr;
954	unsigned			numTokenBits;			// constant, from ciphertext
955	unsigned			numTokenBytes;
956	unsigned char		*longCodePtr;
957	unsigned			numLongCodes;
958	unsigned char		*byteCodePtr;
959	unsigned			numByteCodes;
960	unsigned			tokenDex;
961	unsigned			oddByte = 0;
962	unsigned short		codeWord;
963	unsigned char		codeByte;
964	unsigned			ptextLen = *plainTextLen;	// bytes REMAINING
965	unsigned			above;
966	unsigned			j;
967	unsigned char		blockDesc;
968	dcbReturn			drtn;
969	int					len;
970	queueElt			*src;
971	queueElt			*dst;
972	int					lastWord = 0;
973	queueElt 			*cbufq = &cbuf->queue[0];
974	int					level2 = 0;				// 2nd level comcrypted block
975	unsigned			match;
976	unsigned char		sigSeq;					// signature sequence enable
977	unsigned char		nibble;
978
979	blockDesc = cipherText[CTBO_BLOCK_DESC];
980	if((blockDesc & CBD_MAGIC_MASK) != CBD_MAGIC) {
981		ddprintf(("deComcryptBlock: bad CBD_MAGIC\n"));
982		return DCB_PARSE_ERROR;
983	}
984
985	/*
986	 * Min block size - blockDesc, numLongCodes, numTokens, one token byte,
987	 * one bytecode
988	 */
989	if(cipherTextLen < 5) {
990		return DCB_SHORT;
991	}
992	if((blockDesc & CBD_FULL_BLOCK_MASK) == CBD_FULL_BLOCK) {
993		/*
994		 * # of token bits implied for full block
995		 */
996		numTokenBits  = TOKEN_BITS_FROM_PTEXT(CC_BLOCK_SIZE);
997		numTokenBytes = TOKEN_BYTES_FROM_PTEXT(CC_BLOCK_SIZE);
998		tokenPtr      = cipherText + CTBO_NUM_TOKENS;
999	}
1000	else {
1001		numTokenBits  = cipherText[CTBO_NUM_TOKENS];
1002		numTokenBytes = TOKEN_BYTES_FROM_TOKEN_BITS(numTokenBits);
1003		tokenPtr      = cipherText + CTBO_NUM_TOKENS + 1;
1004	}
1005	longCodePtr = tokenPtr + numTokenBytes;
1006	numLongCodes = cipherText[CTBO_NUM_LONG_CODES];
1007
1008	byteCodePtr  = longCodePtr + (numLongCodes * 2);	// may increment...
1009	if((blockDesc & CBD_BLOCK_TYPE_MASK) == CBD_SINGLE) {
1010		/*
1011		 * # of bytecodes implied from numTokenBits and numLongCodes
1012		 */
1013		numByteCodes = numTokenBits - numLongCodes;
1014	}
1015	else {
1016		/*
1017		 * size of 2nd level comcrypted bytecode specified after longCode
1018		 * array (and before the bytecode itself).
1019		 * Careful, verify that we can read numByteCodes first...
1020		 */
1021		if((unsigned)(byteCodePtr - cipherText) > cipherTextLen) {
1022			return DCB_SHORT;
1023		}
1024		numByteCodes = *byteCodePtr++;
1025		level2 = 1;
1026	}
1027	*blockSize = (unsigned)(byteCodePtr - cipherText) + numByteCodes;
1028	if(*blockSize > cipherTextLen) {
1029		return DCB_SHORT;
1030	}
1031
1032	/*
1033	 * We now know that we have a complete cipherblock. Go for it.
1034	 */
1035	if(level2) {
1036		/*
1037		 * this block's bytecode array contains 2nd level comcrypted bytecodes.
1038		 */
1039		unsigned thisPtext = cbuf->level2BufSize;
1040		unsigned level1CodeSize;
1041
1042		if(cbuf->nextBuf == NULL) {
1043			ddprintf(("2-level comcypt, no nextBuf available!\n"));
1044			return DCB_PARSE_ERROR;
1045		}
1046		drtn = deComcryptBlock(cpriv,
1047			cbuf->nextBuf,
1048			byteCodePtr,
1049			numByteCodes,
1050			cbuf->level2Buf,
1051			&thisPtext,
1052			CCE_END_OF_STREAM,
1053			&level1CodeSize);
1054		switch(drtn) {
1055			case DCB_SHORT:
1056				ddprintf(("CBT_DOUBLE block, incomplete cipherblock in "
1057					"2nd level code\n"));
1058				return DCB_PARSE_ERROR;
1059
1060			case DCB_OUTBUFFER_TOO_SMALL:	// not our fault!
1061			case DCB_PARSE_ERROR:
1062			default:
1063				ddprintf(("2nd-level decomcrypt error (%d)\n", drtn));
1064					return drtn;
1065
1066			case DCB_SUCCESS:
1067				/*
1068				 * Supposedly we passed in exactly one cipherblock...
1069				 */
1070				if(numByteCodes != level1CodeSize) {
1071					ddprintf(("2nd-level decomcrypt: "
1072						"numByteCodes != level1CodeSize\n"));
1073					return DCB_PARSE_ERROR;
1074				}
1075				l2printf(("2nd-level decomcrypt: ciphertext %d "
1076					"numByteCodes %d\n", numByteCodes, thisPtext));
1077				break;
1078		}
1079		byteCodePtr = cbuf->level2Buf;
1080		numByteCodes = thisPtext;
1081	}
1082
1083	if((blockDesc & CBD_ODD_MASK) == CBD_ODD) {
1084		oddByte = 1;
1085	}
1086
1087	/*
1088	 * Skip signature sequence if this was a 2nd level comcrypted block
1089	 */
1090	sigSeq = cpriv->sigSeqEnable && !level2;
1091
1092	for(tokenDex=0; tokenDex<numTokenBits; tokenDex++) {
1093		match = !getToken(tokenPtr, tokenDex);
1094
1095		/*
1096		 * 17 Dec 1997 - Always calculate this regardless of match
1097		 */
1098		nibble = keynybble(cpriv->key, cpriv->keybytes,
1099						  	 (cbuf->nybbleDex)++);
1100
1101		if(match) {
1102			codeByte = *byteCodePtr++;
1103
1104			if(sigSeq) {
1105				codeByte ^= (unsigned char)(cbuf->sigArray[tokenDex]);
1106			}
1107
1108			/*
1109			 * dynamically process the queue for match - 8 bits
1110			 * of ciphercode, 16 bits of plaintext
1111			 */
1112			codeWord = cbufq[codeByte];
1113			above = (cbuf->f1 * codeByte * (16 + nibble)) >> 9;
1114
1115#if		SKIP_NIBBLE_ON_QUEUE_0
1116			if(codeByte == 0) {
1117				/*
1118				 * Special case for top of queue optimization during
1119				 * comcrypt
1120				 */
1121				nibble = cbuf->nybbleDex - 1;
1122			}
1123#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
1124
1125			/*
1126			 * queue[above..codeByte] move one element towards end
1127			 * queue[above] = this codeWord
1128			 */
1129			len = (int)codeByte - (int)above;
1130			if(len > QUEUE_MEMMOVE_THRESH) {
1131				src = &cbufq[above];
1132				dst = src + 1;
1133				len *= sizeof(queueElt);
1134				memmove(dst, src, len);
1135			}
1136			else {
1137				for(j = codeByte; j > above; j--) {
1138					cbufq[j] = cbufq[j-1];
1139				}
1140			}
1141			cbufq[above] = codeWord;
1142		}
1143		else {
1144			/*
1145			 * !match, 16 bits of code
1146			 */
1147			deserializeShort(codeWord, longCodePtr);
1148			if(sigSeq) {
1149				codeWord ^= cbuf->sigArray[tokenDex];
1150			}
1151
1152			if(oddByte && (tokenDex == (numTokenBits - 1))) {
1153				lastWord = 1;
1154				above = 0;
1155#if		SKIP_NIBBLE_ON_QUEUE_0
1156				nibble = cbuf->nybbleDex - 1;
1157#endif	/*SKIP_NIBBLE_ON_QUEUE_0*/
1158			}
1159			else {
1160				longCodePtr += 2;
1161
1162				/*
1163				 * dynamically process the queue for unmatch; skip if this
1164				 * is an oddByte codeword.
1165				 * queue[above...QLEN-1] move one element toward end
1166				 * queue[above] = new codeWord
1167				 */
1168				above = ABOVE(cbuf->f2) + nibble;
1169				len = QLEN - 1 - (int)above;
1170				if(len > QUEUE_MEMMOVE_THRESH) {
1171					src = &cbufq[above];
1172					dst = src + 1;
1173					len *= sizeof(queueElt);
1174					memmove(dst, src, len);
1175				}
1176				else {
1177					for(j=QLEN-1; j > above; j--) {
1178						cbufq[j] = cbufq[j-1];
1179					}
1180				}
1181				cbufq[above] = codeWord;
1182			}
1183		}
1184
1185		if(sigSeq) {
1186			/*
1187			 * Advance signature sequence state machine.
1188			 */
1189			nextSigWord(cbuf, tokenDex+1, match, (above + nibble));
1190		}
1191
1192		/*
1193		 * cook up a byte or two of plainText from code word and invmap[]
1194		 */
1195		if(ptextLen < 1) {
1196			ddprintf(("decryptBlock: ptext overflow (1)\n"));
1197			return DCB_OUTBUFFER_TOO_SMALL;
1198		}
1199		*plainText++ = cpriv->invmap[(codeWord >> 8) & 0xff];
1200		ptextLen--;
1201		if(lastWord) {
1202			/*
1203			 * end of oddByte block.
1204			 */
1205			tokenDex++;	// for sigArray maintenance
1206			break;		// out of main loop
1207		}
1208		else {
1209			if(ptextLen < 1) {
1210				ddprintf(("decryptBlock: ptext overflow (2)\n"));
1211				return DCB_OUTBUFFER_TOO_SMALL;
1212			}
1213			*plainText++ = cpriv->invmap[(codeWord) & 0xff];
1214			ptextLen--;
1215		}
1216	}
1217
1218	/*
1219	 * Prime sigArray state machine for next block.
1220	 */
1221	if(sigSeq) {
1222		cbuf->sigArray[0] = cbuf->sigArray[tokenDex];
1223	}
1224	*plainTextLen = *plainTextLen - ptextLen;
1225	return DCB_SUCCESS;
1226}
1227
1228comcryptReturn deComcryptData(
1229	comcryptObj 			cobj,
1230	unsigned char 			*cipherText,
1231	unsigned 				cipherTextLen,
1232	unsigned char 			*plainText,
1233	unsigned	 			*plainTextLen,	// IN/OUT
1234	comcryptEos 			endOfStream) 	// CCE_END_OF_STREAM, etc.
1235
1236{
1237	comcryptPriv	*cpriv = (comcryptPriv *)cobj;
1238    unsigned char 	*outorigin = plainText;
1239	unsigned		ptextLen = *plainTextLen;
1240	unsigned		thisPtext;				// per block
1241	unsigned		blockSize;
1242	dcbReturn		drtn;
1243	unsigned 		ctextUsed;
1244
1245	/*
1246	 * Snag version from ciphertext, or as much as we can get
1247	 */
1248	while((cpriv->versionBytes < VERSION_BYTES) && cipherTextLen) {
1249		cpriv->version <<= 8;
1250		cpriv->version |= *cipherText;
1251		cpriv->versionBytes++;
1252		cipherText++;
1253		cipherTextLen--;
1254	}
1255
1256	/*
1257	 * Then skip over the remainder of the header (currently spares)
1258	 */
1259	if((cpriv->spareBytes < SPARE_BYTES) && cipherTextLen) {
1260		unsigned toSkip = SPARE_BYTES - cpriv->spareBytes;
1261
1262		if(toSkip > cipherTextLen) {
1263			toSkip = cipherTextLen;
1264		}
1265		cpriv->spareBytes += toSkip;
1266		cipherText += toSkip;
1267		cipherTextLen -= toSkip;
1268	}
1269
1270	if(cipherTextLen == 0) {
1271		*plainTextLen = 0;
1272		return CCR_SUCCESS;
1273	}
1274
1275    if(cpriv->version != VERSION_3_Dec_97) {
1276    	ddprintf(("Incompatible version.\n"));
1277		return CCR_BAD_CIPHERTEXT;
1278    }
1279
1280	while(cipherTextLen != 0) {
1281
1282		/*
1283		 * Main loop. First deal with possible existing partial block.
1284		 */
1285		if(cpriv->cbuf.codeBufLength != 0) {
1286			unsigned toCopy =
1287				cpriv->cbuf.codeBufSize - cpriv->cbuf.codeBufLength;
1288			unsigned origBufSize = cpriv->cbuf.codeBufLength;
1289
1290			if(toCopy > cipherTextLen) {
1291				toCopy = cipherTextLen;
1292			}
1293			memmove(cpriv->cbuf.codeBuf + cpriv->cbuf.codeBufLength,
1294				cipherText, toCopy);
1295			cpriv->cbuf.codeBufLength += toCopy;
1296
1297			thisPtext = ptextLen;
1298			drtn = deComcryptBlock(cpriv,
1299				&cpriv->cbuf,
1300				cpriv->cbuf.codeBuf,
1301				cpriv->cbuf.codeBufLength,
1302				plainText,
1303				&thisPtext,
1304				endOfStream,
1305				&blockSize);
1306			switch(drtn) {
1307				case DCB_SHORT:
1308					/*
1309					 * Incomplete block in codeBuf
1310					 */
1311					if(endOfStream == CCE_END_OF_STREAM) {
1312						/*
1313						 * Caller thinks this is the end, but we need more
1314						 */
1315						ddprintf(("deComcryptData(): CCE_END_OF_STREAM, "
1316							"not end of block\n"));
1317						return CCR_BAD_CIPHERTEXT;
1318					}
1319					cipherTextLen -= toCopy;
1320					if(cipherTextLen != 0) {
1321						/*
1322						 * i.e., codeBuf overflow - could be s/w error? Do
1323						 * we need a bigger buffer?
1324						 */
1325						ddprintf(("deComcryptData: full codeBuf, incomplete "
1326							"block\n"));
1327						return CCR_BAD_CIPHERTEXT;
1328					}
1329					else {
1330						/*
1331						 * OK, stash it and try again
1332						 */
1333						scprintf(("====incomplete codeBuf, codeBufLength %d, "
1334							"cipherTextLen %d\n",
1335							cpriv->cbuf.codeBufLength, toCopy));
1336						break;		// out of main loop (after this switch)
1337					}
1338
1339				case DCB_OUTBUFFER_TOO_SMALL:
1340					ddprintf(("codeBuf decomcrypt error short buf\n"));
1341					return CCR_OUTBUFFER_TOO_SMALL;
1342
1343				case DCB_PARSE_ERROR:
1344				default:
1345					ddprintf(("codeBuf decomcrypt error (%d)\n", drtn));
1346					return CCR_BAD_CIPHERTEXT;
1347
1348				case DCB_SUCCESS:
1349					/*
1350					 * ctextUsed is how much of caller's ciphertext we used
1351					 * in this buffered block
1352					 */
1353					ctextUsed = blockSize - origBufSize;
1354					scprintf(("====decrypted block in codeBuf, blockSize %d, "
1355						"ctextUsed %d, thisPtext %d\n",
1356						blockSize, ctextUsed, thisPtext));
1357					cipherText    += ctextUsed;
1358					cipherTextLen -= ctextUsed;
1359					plainText     += thisPtext;
1360					ptextLen      -= thisPtext;
1361					cpriv->cbuf.codeBufLength = 0;
1362					break;
1363			}
1364
1365			/*
1366			 * We might have used up all of caller's cipherText processing
1367			 * codeBuf...
1368			 */
1369			if(cipherTextLen == 0) {
1370				break;				// out of main loop
1371			}
1372
1373		}	/* buffered ciphertext in codeBuf */
1374
1375		/*
1376		 * Snarf ciphertext, one block at a time.
1377		 */
1378
1379		thisPtext = ptextLen;
1380		drtn = deComcryptBlock(cpriv,
1381			&cpriv->cbuf,
1382			cipherText,
1383			cipherTextLen,
1384			plainText,
1385			&thisPtext,
1386			endOfStream,
1387			&blockSize);
1388		switch(drtn) {
1389			case DCB_SHORT:
1390				/*
1391				 * Incomplete block
1392				 */
1393				if(endOfStream == CCE_END_OF_STREAM) {
1394					ddprintf(("deComcryptData(): CCE_END_OF_STREAM, not end of "
1395						"block (2)\n"));
1396					return CCR_BAD_CIPHERTEXT;
1397				}
1398				if(cipherTextLen >
1399				       (cpriv->cbuf.codeBufSize - cpriv->cbuf.codeBufLength)) {
1400					ddprintf(("deComcryptData(): codeBuf overflow!\n"));
1401					return CCR_BAD_CIPHERTEXT;
1402				}
1403				memmove(cpriv->cbuf.codeBuf + cpriv->cbuf.codeBufLength,
1404					cipherText, cipherTextLen);
1405				cpriv->cbuf.codeBufLength += cipherTextLen;
1406				cipherTextLen = 0;
1407				scprintf(("====Incomplete block, cipherTextLen %d "
1408					"codeBufLength %d\n", cipherTextLen,
1409					cpriv->cbuf.codeBufLength));
1410				break;		// actually out of main loop
1411
1412		    case DCB_PARSE_ERROR:
1413			case DCB_OUTBUFFER_TOO_SMALL:
1414			default:
1415				return CCR_BAD_CIPHERTEXT;
1416
1417			case DCB_SUCCESS:
1418				if(ptextLen < thisPtext) {
1419					/*
1420					 * Software error
1421					 */
1422					ddprintf(("deComcryptData: undetected ptext "
1423						"overflow (2)\n"));
1424					return CCR_BAD_CIPHERTEXT;
1425				}
1426				plainText     += thisPtext;
1427				ptextLen      -= thisPtext;
1428				cipherText    += blockSize;
1429				cipherTextLen -= blockSize;
1430				scprintf(("====decrypted one block, blockSize %d "
1431					"thisPtext %d\n", blockSize, thisPtext));
1432				break;
1433		}
1434	}	/* main loop */
1435
1436	*plainTextLen = (unsigned)(plainText - outorigin);
1437	return CCR_SUCCESS;
1438}
1439