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