/ OSX / libsecurity_comcryption / lib / comcryption.c
comcryption.c
   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  
  34  unsigned comProfEnable;
  35  comprof_t cmcTotal;
  36  comprof_t cmcQueSearch;
  37  comprof_t cmcQueMatchMove;
  38  comprof_t cmcQueMissMove;
  39  comprof_t cmcLevel2;
  40  comprof_t cmcPerWordOhead;
  41  
  42  #endif	/*COM_PROFILE*/
  43  
  44  void 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   */
  55  comcryptObj 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   */
 114  comcryptReturn 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   */
 181  void 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   */
 204  unsigned 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   */
 305  unsigned 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   */
 391  static 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   */
 863  comcryptReturn 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   */
 933  typedef 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   */
 943  static 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  
1228  comcryptReturn 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  }