2 * Copyright (c) 1997,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
28 #include "comcryption.h"
30 #include "comcryptPriv.h"
34 unsigned comProfEnable
;
36 comprof_t cmcQueSearch
;
37 comprof_t cmcQueMatchMove
;
38 comprof_t cmcQueMissMove
;
40 comprof_t cmcPerWordOhead
;
42 #endif /*COM_PROFILE*/
44 void comMallocRegister(comMallocExternFcn
*mallocExtern
,
45 comFreeExternFcn
*freeExtern
)
47 comMallocExt
= mallocExtern
;
48 comFreeExt
= freeExtern
;
52 * Call once at startup. The resulting comcryptObj can be reused multiple
55 comcryptObj
comcryptAlloc(void)
57 comcryptPriv
*cpriv
= (comcryptPriv
*) ascMalloc(sizeof(comcryptPriv
));
62 memset(cpriv
, 0, sizeof(comcryptPriv
));
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*/
70 if(cpriv
->key
== NULL
) {
73 cpriv
->map
= (unsigned char *)ascMalloc(256);
74 cpriv
->invmap
= (unsigned char *)ascMalloc(256);
75 if((cpriv
->map
== NULL
) || (cpriv
->invmap
== NULL
)) {
78 mallocCodeBufs(&cpriv
->cbuf
);
79 if((cpriv
->cbuf
.codeBuf
== NULL
) ||
80 (cpriv
->cbuf
.level2Buf
== NULL
)) {
84 if(cpriv
->cbuf
.lookAhead
== NULL
) {
90 * Hard coded limit of two levels of comcryption
92 cpriv
->cbuf
.nextBuf
= (comcryptBuf
*)ascMalloc(sizeof(comcryptBuf
));
93 if(cpriv
->cbuf
.nextBuf
== NULL
) {
96 mallocCodeBufs(cpriv
->cbuf
.nextBuf
);
97 if((cpriv
->cbuf
.nextBuf
->codeBuf
== NULL
) ||
98 (cpriv
->cbuf
.nextBuf
->level2Buf
== NULL
)) {
102 if(cpriv
->cbuf
.nextBuf
->lookAhead
== NULL
) {
107 cpriv
->cbuf
.nextBuf
->nextBuf
= NULL
;
112 * Call this before starting every stream process
114 comcryptReturn
comcryptInit(
116 const unsigned char *key
,
118 comcryptOptimize optimize
) // CCO_SIZE, etc.
120 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
123 #if COMCRYPT_EXPORT_ONLY
125 * FIXME - NSA might not be satisfied with this, may have to enforce
128 maxKeySize
= EXPORT_KEY_SIZE
;
129 #else /*COMCRYPT_EXPORT_ONLY*/
130 maxKeySize
= COMCRYPT_MAX_KEYLENGTH
;
131 #endif /*COMCRYPT_EXPORT_ONLY*/
133 if(keyLen
> maxKeySize
) {
136 memmove(cpriv
->key
, key
, keyLen
);
137 cpriv
->keybytes
= keyLen
;
138 cpriv
->cbuf
.codeBufLength
= 0;
139 cpriv
->cbuf
.nextBuf
->codeBufLength
= 0;
141 cpriv
->versionBytes
= 0;
142 cpriv
->spareBytes
= 0;
143 cpriv
->optimize
= optimize
;
146 * Derive feature enable bits from optimize arg. This is highly likely
149 cpriv
->level2enable
= 1;
150 cpriv
->sigSeqEnable
= 1;
153 cpriv
->level2enable
= 0;
156 cpriv
->sigSeqEnable
= 0;
163 #else /* QUEUE_LOOKAHEAD */
165 #endif /* QUEUE_LOOKAHEAD */
168 * init queue and maps
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
);
179 * Free a comcryptObj object obtained via comcryptAlloc()
181 void comcryptObjFree(comcryptObj cobj
)
183 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
185 if(cpriv
->key
!= NULL
) {
188 if(cpriv
->map
!= NULL
) {
191 if(cpriv
->invmap
!= NULL
) {
192 ascFree(cpriv
->invmap
);
194 freeCodeBufs(&cpriv
->cbuf
);
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.
204 unsigned comcryptMaxInBufSize(comcryptObj cobj
,
209 unsigned minCblockSize
;
213 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
214 unsigned ptextFromCodeBuf
;
219 * Worst case: no compression. Also, establish a minimum
220 * ciphertext size to accomodate header and one block.
222 minCblockSize
= MIN_CBLOCK_SIZE
;
223 if(cpriv
->versionBytes
== 0) {
224 minCblockSize
+= CTEXT_HDR_SIZE
;
226 if(outBufSize
< (minCblockSize
)) {
229 if(cpriv
->versionBytes
== 0) {
230 outBufSize
-= CTEXT_HDR_SIZE
;
232 fullBlocks
= outBufSize
/ MAX_CBLOCK_SIZE
;
233 rtn
= (fullBlocks
* CC_BLOCK_SIZE
); // bytes of ptext
236 * code must be even aligned, then chop off one for odd ptext
243 resid
= outBufSize
% MAX_CBLOCK_SIZE
;
248 * Account for resid block overhead
250 if(rtn
< MIN_CBLOCK_SIZE
) {
253 rtn
-= MIN_CBLOCK_SIZE
;
255 tokenBytes
= TOKEN_BYTES_FROM_PTEXT(resid
);
256 if(rtn
<= tokenBytes
) {
261 if(rtn
> INBUF_TRUNC_THRESH
) {
263 * Truncate to even block size to minimize partial cipherblocks
265 rtn
&= ~(CC_BLOCK_SIZE
- 1);
269 case CCOP_DECOMCRYPT
:
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...
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 */
282 /* can decrypt (this much plainText - ptextFromCodeBuf) / 4 */
283 rtn
= (outBufSize
- ptextFromCodeBuf
) / 4;
286 /* may be able to handle a bit extra for initial decrypt... */
287 if(cpriv
->versionBytes
< VERSION_BYTES
) {
288 rtn
+= (VERSION_BYTES
- cpriv
->versionBytes
);
290 if(cpriv
->spareBytes
< SPARE_BYTES
) {
291 rtn
+= (SPARE_BYTES
- cpriv
->spareBytes
);
296 ddprintf(("bogus op (%d) in comcryptMaxInBufSize()\n", op
));
302 * Return the maximum output buffer size for specified input buffer size.
303 * Output buffer size will always be larger than input buffer size.
305 unsigned comcryptMaxOutBufSize(comcryptObj cobj
,
313 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
317 fullBlocks
= inBufSize
/ CC_BLOCK_SIZE
;
318 rtn
= fullBlocks
* MAX_CBLOCK_SIZE
;
319 resid
= inBufSize
% CC_BLOCK_SIZE
;
324 unsigned tokenBytes
= TOKEN_BYTES_FROM_PTEXT(resid
);
326 rtn
+= MIN_CBLOCK_SIZE
;
328 rtn
+= resid
; // no compression
330 rtn
++; // oddByte uses extra
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
339 case CCOP_DECOMCRYPT
:
341 * Here assume max compression, including resid block in codeBuf
343 inBufSize
+= cpriv
->cbuf
.codeBufLength
;
345 /* may be able to handle a bit extra for initial decrypt... */
347 if(cpriv
->versionBytes
< VERSION_BYTES
) {
348 delta
= VERSION_BYTES
- cpriv
->versionBytes
;
349 if(inBufSize
> delta
) {
356 if(cpriv
->spareBytes
< SPARE_BYTES
) {
357 delta
= SPARE_BYTES
- cpriv
->spareBytes
;
358 if(inBufSize
> delta
) {
370 ddprintf(("bogus op (%d) in comcryptMaxOutBufSize()\n", op
));
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.
380 #define QUEUE_MEMMOVE_THRESH 3
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].
389 * Comcrypt one block.
391 static comcryptReturn
comcryptBlock(
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
)
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;
412 unsigned tokenDex
= 0; // index into array of token bits
414 unsigned numLongCodes
= 0;
415 unsigned numByteCodes
= 0;
416 unsigned totalCipherTextLen
;
418 unsigned jmatchTotal
= 0;
421 unsigned char blockDesc
= CBD_MAGIC
;
422 unsigned fullBlock
= 0;
426 queueElt
*cbufq
= &cbuf
->queue
[0];
429 * 'nibble' is added to 'above' in the call to nextSigWord() for
430 * additional security.
432 * Normal case : nibble = keynybble()
433 * last word on odd byte : nibble = nibbleDex
434 * hit on queue q : nibble = nibbleDex (optimize to avoid keynybble()
437 unsigned char nibble
;
442 if(testLookAhead(cbuf
, 0, 0)) {
447 laprintf(("comcryptBlock recurs level %d\n", recursLevel
));
450 * Set up ptrs for the three arrays we'll be writing
452 tokenPtr
= cipherText
+ CTBO_NUM_TOKENS
+ 1;
453 if(plainTextLen
>= (CC_BLOCK_SIZE
- 1)) {
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!
459 numTokenBytes
= CC_BLOCK_SIZE
>> 4;
461 blockDesc
|= CBD_FULL_BLOCK
;
465 numTokenBytes
= (plainTextLen
+ 15) >> 4;
467 longCodePtr
= tokenPtr
+ numTokenBytes
;
468 startLongCodePtr
= longCodePtr
;
469 byteCodePtr
= cbuf
->codeBuf
;
470 startTokenPtr
= tokenPtr
;
472 if((unsigned)(longCodePtr
- cipherText
) > *cipherTextLen
) {
473 ddprintf(("comcryptBlock: short block (1)\n"));
474 return CCR_OUTBUFFER_TOO_SMALL
;
476 memset(tokenPtr
, 0, numTokenBytes
);
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.
483 while(plainTextLen
!= 0) {
486 * assemble a 16-bit word from two bytes if possible
488 if(plainTextLen
== 1) {
492 codeWord
= ((unsigned short)(cpriv
->map
[*plainText
]) << 8) |
493 cpriv
->map
[0]; // a bit of obfuscation - mapped zero
495 blockDesc
|= CBD_ODD
;
499 codeWord
= ((unsigned short)(cpriv
->map
[*plainText
]) << 8) |
500 (unsigned short)(cpriv
->map
[plainText
[1]]);
506 * Calibrate how much profiling is costing us.
509 COMPROF_END(cmcPerWordOhead
);
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.
516 COMPROF_START
; /* cmcQueSearch */
518 do { /* while 0 - for easy breaks w/o goto */
521 * First handle some optimizations and special cases
524 break; // force longcode
528 if(cbufq
[0] == codeWord
) {
534 #endif /*QUEUE_PEEK*/
536 if(cpriv
->laEnable
&& !inQueue(cbuf
, codeWord
)) {
541 * OK, do the gruntwork search
543 for(j
=0; j
< QLEN
; j
++) {
544 if(cbufq
[j
] == codeWord
) {
552 if(cpriv
->laEnable
&& !match
) {
553 printf("inQueue, not found in queue!\n");
558 * Search for duplicates.
561 for(j
=jmatch
+1; j
<QLEN
; j
++) {
562 if(cbufq
[j
] == codeWord
) {
563 printf("***Huh! Dup queue entry codeWord 0x%x jmatch "
565 codeWord
, jmatch
, j
);
570 #endif /*COM_LA_DEBUG*/
573 COMPROF_END(cmcQueSearch
);
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.
580 * New 17 Dec 1997 - always calculate keynibble for use in signature
583 #if !SKIP_NIBBLE_ON_QUEUE_0
584 nibble
= keynybble(cpriv
->key
, cpriv
->keybytes
,
585 (cbuf
->nybbleDex
)++);
586 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
591 * 16-bit symbol is in queue. 8 bits of ciphertext, token bit is 0.
595 * Optimization: jmatch = 0. Keep state machine in sync,
596 * but skip queue update.
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*/
605 #if SKIP_NIBBLE_ON_QUEUE_0
606 nibble
= keynybble(cpriv
->key
, cpriv
->keybytes
,
607 (cbuf
->nybbleDex
)++);
608 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
610 above
= (cbuf
->f1
* jmatch
* (16 + nibble
)) >> 9;
613 * queue[above..(jmatch-1)] move one element towards end
614 * queue[above] = this codeWord
616 laprintf(("...queue hit, moving 0x%x from 0x%x to 0x%x\n",
617 codeWord
, jmatch
, above
));
619 len
= (int)jmatch
- (int)above
;
620 if(len
> QUEUE_MEMMOVE_THRESH
) {
623 len
*= sizeof(queueElt
);
624 memmove(dst
, src
, len
);
627 for(j
= jmatch
; j
>above
; j
--) {
628 cbufq
[j
] = cbufq
[j
-1];
632 cbufq
[above
] = codeWord
;
634 if(testLookAhead(cbuf
, above
, jmatch
)) {
637 #endif /*COM_LA_DEBUG*/
639 COMPROF_END(cmcQueMatchMove
);
642 incr1byteFrags(recursLevel
);
643 jmatchTotal
+= jmatch
;
645 else if(oddByte
== 0) {
647 * 16-bit symbol is not in queue. 16 bits of ciphertext.
650 * queue[above...QLEN-1] move one element toward end
651 * queue[QLEN-1] discarded
652 * queue[above] = new codeword
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
658 #if SKIP_NIBBLE_ON_QUEUE_0
659 nibble
= keynybble(cpriv
->key
, cpriv
->keybytes
,
660 (cbuf
->nybbleDex
)++);
661 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
663 above
= ABOVE(cbuf
->f2
) + nibble
;
667 printf("Hey Doug! above %d QLEN %d\n", above
, QLEN
);
672 laprintf(("...queue miss, adding 0x%x at 0x%x, deleting 0x%x\n",
673 codeWord
, above
, cbufq
[QLEN
-1]));
675 if(cpriv
->laEnable
) {
676 markInQueue(cbuf
, codeWord
, 1); // new entry
677 markInQueue(cbuf
, cbufq
[QLEN
-1], 0); // bumped out
680 len
= QLEN
- 1 - (int)above
;
681 if(len
> QUEUE_MEMMOVE_THRESH
) {
684 len
*= sizeof(queueElt
);
685 memmove(dst
, src
, len
);
688 for(j
=QLEN
-1; j
> above
; j
--) {
689 cbufq
[j
] = cbufq
[j
-1];
693 cbufq
[above
] = codeWord
;
696 if(testLookAhead(cbuf
, above
, 0)) {
699 #endif /*COM_LA_DEBUG*/
701 COMPROF_END(cmcQueMissMove
);
702 incr2byteFrags(recursLevel
);
706 * Odd byte case, at least gather stats.
708 incr2byteFrags(recursLevel
);
711 * ...and keep this in sync for signature sequence
714 #if SKIP_NIBBLE_ON_QUEUE_0
715 nibble
= (cbuf
->nybbleDex
)++;
716 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
719 updateToken(tokenPtr
, tokenDex
, !match
);
723 *byteCodePtr
++ = codeWord
& 0xff;
727 serializeShort(codeWord
, longCodePtr
);
731 if(cpriv
->sigSeqEnable
) {
732 nextSigWord(cbuf
, tokenDex
, match
, (above
+ nibble
));
737 if(numTokenBytes
!= ((tokenDex
+ 7) >> 3)) {
738 ddprintf(("comcryptBlock: numTokenBytes (%d), tokenDex (%d)\n",
739 numTokenBytes
, tokenDex
));
744 * We already wrote tokens and longcode to cipherText; verify we
747 totalCipherTextLen
= (unsigned)(longCodePtr
- startCtextPtr
);
748 if(*cipherTextLen
< totalCipherTextLen
) {
749 ddprintf(("comcryptBlock: short block (2)\n"));
750 return CCR_OUTBUFFER_TOO_SMALL
;
753 cipherText
[CTBO_NUM_TOKENS
] = tokenDex
;
755 cipherText
[CTBO_NUM_LONG_CODES
] = numLongCodes
;
758 if(tokenDex
> MAX_TOKENS
) {
759 ddprintf(("comcryptBlock: counter overflow!\n"));
762 if((numByteCodes
+ numLongCodes
) != tokenDex
) {
763 ddprintf(("comcryptBlock: counter mismatch!\n"));
769 * See if doing a second level comcryption makes sense.
771 destByteCodePtr
= startLongCodePtr
+ (numLongCodes
* 2);
772 if(numByteCodes
> 0) {
773 jmatchAvg
= jmatchTotal
/ numByteCodes
;
776 jmatchAvg
= cbuf
->jmatchThresh
+ 1;
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
784 unsigned thisCtext
= cbuf
->level2BufSize
;
787 crtn
= comcryptBlock(cpriv
,
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
805 totalCipherTextLen
+= (thisCtext
+ 1);
806 if(*cipherTextLen
< totalCipherTextLen
) {
807 ddprintf(("comcryptBlock: short block (3)\n"));
808 return CCR_OUTBUFFER_TOO_SMALL
;
810 *destByteCodePtr
++ = thisCtext
;
811 COMPROF_END(cmcLevel2
);
812 memmove(destByteCodePtr
, cbuf
->level2Buf
, thisCtext
);
813 blockDesc
|= CBD_DOUBLE
;
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);
824 * Normal one-level comcryption. Write byteCodes to ciphertext.
825 * numByteCodes is inferred.
827 totalCipherTextLen
+= numByteCodes
;
828 if(*cipherTextLen
< totalCipherTextLen
) {
829 ddprintf(("comcryptBlock: short block (3)\n"));
830 return CCR_OUTBUFFER_TOO_SMALL
;
832 memmove(destByteCodePtr
, cbuf
->codeBuf
, numByteCodes
);
833 blockDesc
|= CBD_SINGLE
;
834 if(recursLevel
== 0) {
835 incrComStat(level1blocks
, 1);
837 /* else this is a 2nd-level, our caller will count */
840 * obfuscate via sigArray (only when we're NOT doing 2nd level
843 if(cpriv
->sigSeqEnable
) {
844 sigMunge(cbuf
, startTokenPtr
, tokenDex
,
845 destByteCodePtr
, startLongCodePtr
);
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.
852 cbuf
->sigArray
[0] = cbuf
->sigArray
[tokenDex
];
855 cipherText
[CTBO_BLOCK_DESC
] = blockDesc
;
856 *cipherTextLen
= totalCipherTextLen
;
861 * Main public encrypt function.
863 comcryptReturn
comcryptData(
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.
871 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
872 unsigned ctextLen
= *cipherTextLen
;
879 incrComStat(plaintextBytes
, plainTextLen
);
880 if(cpriv
->versionBytes
== 0) {
882 * First, put header (version, spare) into head of ciphertext.
884 if(ctextLen
< CTEXT_HDR_SIZE
) {
885 ddprintf(("comcryptData: overflow (0)\n"));
886 return CCR_OUTBUFFER_TOO_SMALL
;
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
;
897 * OK, grind it out, one block at a time.
899 while (plainTextLen
!= 0) {
900 thisPtext
= CC_BLOCK_SIZE
;
901 if(thisPtext
> plainTextLen
) {
902 thisPtext
= plainTextLen
;
904 thisCtext
= ctextLen
;
905 crtn
= comcryptBlock(cpriv
,
915 plainText
+= thisPtext
;
916 plainTextLen
-= thisPtext
;
917 if(thisCtext
> ctextLen
) {
918 ddprintf(("comcryptData: undetected ciphertext overlow\n"));
919 return CCR_OUTBUFFER_TOO_SMALL
;
921 cipherText
+= thisCtext
;
922 ctextLen
-= thisCtext
;
924 *cipherTextLen
= *cipherTextLen
- ctextLen
;
925 incrComStat(ciphertextBytes
, *cipherTextLen
);
926 COMPROF_END(cmcTotal
);
931 * Return values from deComcryptBlock().
935 DCB_SHORT
, // incomplete block, try again with more ciphertext
936 DCB_PARSE_ERROR
, // bad block
937 DCB_OUTBUFFER_TOO_SMALL
941 * Assumes exactly one block of ciphertext, error otherwise.
943 static dcbReturn
deComcryptBlock(
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
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
;
961 unsigned oddByte
= 0;
962 unsigned short codeWord
;
963 unsigned char codeByte
;
964 unsigned ptextLen
= *plainTextLen
; // bytes REMAINING
967 unsigned char blockDesc
;
973 queueElt
*cbufq
= &cbuf
->queue
[0];
974 int level2
= 0; // 2nd level comcrypted block
976 unsigned char sigSeq
; // signature sequence enable
977 unsigned char nibble
;
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
;
986 * Min block size - blockDesc, numLongCodes, numTokens, one token byte,
989 if(cipherTextLen
< 5) {
992 if((blockDesc
& CBD_FULL_BLOCK_MASK
) == CBD_FULL_BLOCK
) {
994 * # of token bits implied for full block
996 numTokenBits
= TOKEN_BITS_FROM_PTEXT(CC_BLOCK_SIZE
);
997 numTokenBytes
= TOKEN_BYTES_FROM_PTEXT(CC_BLOCK_SIZE
);
998 tokenPtr
= cipherText
+ CTBO_NUM_TOKENS
;
1001 numTokenBits
= cipherText
[CTBO_NUM_TOKENS
];
1002 numTokenBytes
= TOKEN_BYTES_FROM_TOKEN_BITS(numTokenBits
);
1003 tokenPtr
= cipherText
+ CTBO_NUM_TOKENS
+ 1;
1005 longCodePtr
= tokenPtr
+ numTokenBytes
;
1006 numLongCodes
= cipherText
[CTBO_NUM_LONG_CODES
];
1008 byteCodePtr
= longCodePtr
+ (numLongCodes
* 2); // may increment...
1009 if((blockDesc
& CBD_BLOCK_TYPE_MASK
) == CBD_SINGLE
) {
1011 * # of bytecodes implied from numTokenBits and numLongCodes
1013 numByteCodes
= numTokenBits
- numLongCodes
;
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...
1021 if((unsigned)(byteCodePtr
- cipherText
) > cipherTextLen
) {
1024 numByteCodes
= *byteCodePtr
++;
1027 *blockSize
= (unsigned)(byteCodePtr
- cipherText
) + numByteCodes
;
1028 if(*blockSize
> cipherTextLen
) {
1033 * We now know that we have a complete cipherblock. Go for it.
1037 * this block's bytecode array contains 2nd level comcrypted bytecodes.
1039 unsigned thisPtext
= cbuf
->level2BufSize
;
1040 unsigned level1CodeSize
;
1042 if(cbuf
->nextBuf
== NULL
) {
1043 ddprintf(("2-level comcypt, no nextBuf available!\n"));
1044 return DCB_PARSE_ERROR
;
1046 drtn
= deComcryptBlock(cpriv
,
1056 ddprintf(("CBT_DOUBLE block, incomplete cipherblock in "
1057 "2nd level code\n"));
1058 return DCB_PARSE_ERROR
;
1060 case DCB_OUTBUFFER_TOO_SMALL
: // not our fault!
1061 case DCB_PARSE_ERROR
:
1063 ddprintf(("2nd-level decomcrypt error (%d)\n", drtn
));
1068 * Supposedly we passed in exactly one cipherblock...
1070 if(numByteCodes
!= level1CodeSize
) {
1071 ddprintf(("2nd-level decomcrypt: "
1072 "numByteCodes != level1CodeSize\n"));
1073 return DCB_PARSE_ERROR
;
1075 l2printf(("2nd-level decomcrypt: ciphertext %d "
1076 "numByteCodes %d\n", numByteCodes
, thisPtext
));
1079 byteCodePtr
= cbuf
->level2Buf
;
1080 numByteCodes
= thisPtext
;
1083 if((blockDesc
& CBD_ODD_MASK
) == CBD_ODD
) {
1088 * Skip signature sequence if this was a 2nd level comcrypted block
1090 sigSeq
= cpriv
->sigSeqEnable
&& !level2
;
1092 for(tokenDex
=0; tokenDex
<numTokenBits
; tokenDex
++) {
1093 match
= !getToken(tokenPtr
, tokenDex
);
1096 * 17 Dec 1997 - Always calculate this regardless of match
1098 nibble
= keynybble(cpriv
->key
, cpriv
->keybytes
,
1099 (cbuf
->nybbleDex
)++);
1102 codeByte
= *byteCodePtr
++;
1105 codeByte
^= (unsigned char)(cbuf
->sigArray
[tokenDex
]);
1109 * dynamically process the queue for match - 8 bits
1110 * of ciphercode, 16 bits of plaintext
1112 codeWord
= cbufq
[codeByte
];
1113 above
= (cbuf
->f1
* codeByte
* (16 + nibble
)) >> 9;
1115 #if SKIP_NIBBLE_ON_QUEUE_0
1118 * Special case for top of queue optimization during
1121 nibble
= cbuf
->nybbleDex
- 1;
1123 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
1126 * queue[above..codeByte] move one element towards end
1127 * queue[above] = this codeWord
1129 len
= (int)codeByte
- (int)above
;
1130 if(len
> QUEUE_MEMMOVE_THRESH
) {
1131 src
= &cbufq
[above
];
1133 len
*= sizeof(queueElt
);
1134 memmove(dst
, src
, len
);
1137 for(j
= codeByte
; j
> above
; j
--) {
1138 cbufq
[j
] = cbufq
[j
-1];
1141 cbufq
[above
] = codeWord
;
1145 * !match, 16 bits of code
1147 deserializeShort(codeWord
, longCodePtr
);
1149 codeWord
^= cbuf
->sigArray
[tokenDex
];
1152 if(oddByte
&& (tokenDex
== (numTokenBits
- 1))) {
1155 #if SKIP_NIBBLE_ON_QUEUE_0
1156 nibble
= cbuf
->nybbleDex
- 1;
1157 #endif /*SKIP_NIBBLE_ON_QUEUE_0*/
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
1168 above
= ABOVE(cbuf
->f2
) + nibble
;
1169 len
= QLEN
- 1 - (int)above
;
1170 if(len
> QUEUE_MEMMOVE_THRESH
) {
1171 src
= &cbufq
[above
];
1173 len
*= sizeof(queueElt
);
1174 memmove(dst
, src
, len
);
1177 for(j
=QLEN
-1; j
> above
; j
--) {
1178 cbufq
[j
] = cbufq
[j
-1];
1181 cbufq
[above
] = codeWord
;
1187 * Advance signature sequence state machine.
1189 nextSigWord(cbuf
, tokenDex
+1, match
, (above
+ nibble
));
1193 * cook up a byte or two of plainText from code word and invmap[]
1196 ddprintf(("decryptBlock: ptext overflow (1)\n"));
1197 return DCB_OUTBUFFER_TOO_SMALL
;
1199 *plainText
++ = cpriv
->invmap
[(codeWord
>> 8) & 0xff];
1203 * end of oddByte block.
1205 tokenDex
++; // for sigArray maintenance
1206 break; // out of main loop
1210 ddprintf(("decryptBlock: ptext overflow (2)\n"));
1211 return DCB_OUTBUFFER_TOO_SMALL
;
1213 *plainText
++ = cpriv
->invmap
[(codeWord
) & 0xff];
1219 * Prime sigArray state machine for next block.
1222 cbuf
->sigArray
[0] = cbuf
->sigArray
[tokenDex
];
1224 *plainTextLen
= *plainTextLen
- ptextLen
;
1228 comcryptReturn
deComcryptData(
1230 unsigned char *cipherText
,
1231 unsigned cipherTextLen
,
1232 unsigned char *plainText
,
1233 unsigned *plainTextLen
, // IN/OUT
1234 comcryptEos endOfStream
) // CCE_END_OF_STREAM, etc.
1237 comcryptPriv
*cpriv
= (comcryptPriv
*)cobj
;
1238 unsigned char *outorigin
= plainText
;
1239 unsigned ptextLen
= *plainTextLen
;
1240 unsigned thisPtext
; // per block
1246 * Snag version from ciphertext, or as much as we can get
1248 while((cpriv
->versionBytes
< VERSION_BYTES
) && cipherTextLen
) {
1249 cpriv
->version
<<= 8;
1250 cpriv
->version
|= *cipherText
;
1251 cpriv
->versionBytes
++;
1257 * Then skip over the remainder of the header (currently spares)
1259 if((cpriv
->spareBytes
< SPARE_BYTES
) && cipherTextLen
) {
1260 unsigned toSkip
= SPARE_BYTES
- cpriv
->spareBytes
;
1262 if(toSkip
> cipherTextLen
) {
1263 toSkip
= cipherTextLen
;
1265 cpriv
->spareBytes
+= toSkip
;
1266 cipherText
+= toSkip
;
1267 cipherTextLen
-= toSkip
;
1270 if(cipherTextLen
== 0) {
1275 if(cpriv
->version
!= VERSION_3_Dec_97
) {
1276 ddprintf(("Incompatible version.\n"));
1277 return CCR_BAD_CIPHERTEXT
;
1280 while(cipherTextLen
!= 0) {
1283 * Main loop. First deal with possible existing partial block.
1285 if(cpriv
->cbuf
.codeBufLength
!= 0) {
1287 cpriv
->cbuf
.codeBufSize
- cpriv
->cbuf
.codeBufLength
;
1288 unsigned origBufSize
= cpriv
->cbuf
.codeBufLength
;
1290 if(toCopy
> cipherTextLen
) {
1291 toCopy
= cipherTextLen
;
1293 memmove(cpriv
->cbuf
.codeBuf
+ cpriv
->cbuf
.codeBufLength
,
1294 cipherText
, toCopy
);
1295 cpriv
->cbuf
.codeBufLength
+= toCopy
;
1297 thisPtext
= ptextLen
;
1298 drtn
= deComcryptBlock(cpriv
,
1300 cpriv
->cbuf
.codeBuf
,
1301 cpriv
->cbuf
.codeBufLength
,
1309 * Incomplete block in codeBuf
1311 if(endOfStream
== CCE_END_OF_STREAM
) {
1313 * Caller thinks this is the end, but we need more
1315 ddprintf(("deComcryptData(): CCE_END_OF_STREAM, "
1316 "not end of block\n"));
1317 return CCR_BAD_CIPHERTEXT
;
1319 cipherTextLen
-= toCopy
;
1320 if(cipherTextLen
!= 0) {
1322 * i.e., codeBuf overflow - could be s/w error? Do
1323 * we need a bigger buffer?
1325 ddprintf(("deComcryptData: full codeBuf, incomplete "
1327 return CCR_BAD_CIPHERTEXT
;
1331 * OK, stash it and try again
1333 scprintf(("====incomplete codeBuf, codeBufLength %d, "
1334 "cipherTextLen %d\n",
1335 cpriv
->cbuf
.codeBufLength
, toCopy
));
1336 break; // out of main loop (after this switch)
1339 case DCB_OUTBUFFER_TOO_SMALL
:
1340 ddprintf(("codeBuf decomcrypt error short buf\n"));
1341 return CCR_OUTBUFFER_TOO_SMALL
;
1343 case DCB_PARSE_ERROR
:
1345 ddprintf(("codeBuf decomcrypt error (%d)\n", drtn
));
1346 return CCR_BAD_CIPHERTEXT
;
1350 * ctextUsed is how much of caller's ciphertext we used
1351 * in this buffered block
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;
1366 * We might have used up all of caller's cipherText processing
1369 if(cipherTextLen
== 0) {
1370 break; // out of main loop
1373 } /* buffered ciphertext in codeBuf */
1376 * Snarf ciphertext, one block at a time.
1379 thisPtext
= ptextLen
;
1380 drtn
= deComcryptBlock(cpriv
,
1393 if(endOfStream
== CCE_END_OF_STREAM
) {
1394 ddprintf(("deComcryptData(): CCE_END_OF_STREAM, not end of "
1396 return CCR_BAD_CIPHERTEXT
;
1399 (cpriv
->cbuf
.codeBufSize
- cpriv
->cbuf
.codeBufLength
)) {
1400 ddprintf(("deComcryptData(): codeBuf overflow!\n"));
1401 return CCR_BAD_CIPHERTEXT
;
1403 memmove(cpriv
->cbuf
.codeBuf
+ cpriv
->cbuf
.codeBufLength
,
1404 cipherText
, cipherTextLen
);
1405 cpriv
->cbuf
.codeBufLength
+= cipherTextLen
;
1407 scprintf(("====Incomplete block, cipherTextLen %d "
1408 "codeBufLength %d\n", cipherTextLen
,
1409 cpriv
->cbuf
.codeBufLength
));
1410 break; // actually out of main loop
1412 case DCB_PARSE_ERROR
:
1413 case DCB_OUTBUFFER_TOO_SMALL
:
1415 return CCR_BAD_CIPHERTEXT
;
1418 if(ptextLen
< thisPtext
) {
1422 ddprintf(("deComcryptData: undetected ptext "
1424 return CCR_BAD_CIPHERTEXT
;
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
));
1436 *plainTextLen
= (unsigned)(plainText
- outorigin
);