]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd A |
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 | */ | |
b1ab9ed8 | 23 | |
b1ab9ed8 A |
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 | */ | |
427c49bc | 55 | comcryptObj comcryptAlloc(void) |
b1ab9ed8 A |
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 | */ | |
427c49bc | 747 | totalCipherTextLen = (unsigned)(longCodePtr - startCtextPtr); |
b1ab9ed8 A |
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 | } | |
427c49bc | 1027 | *blockSize = (unsigned)(byteCodePtr - cipherText) + numByteCodes; |
b1ab9ed8 A |
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 | ||
427c49bc | 1436 | *plainTextLen = (unsigned)(plainText - outorigin); |
b1ab9ed8 A |
1437 | return CCR_SUCCESS; |
1438 | } |