1/* 2 File: comcryptPriv.c 3 4 Contains: private routines for comcryption library. 5 6 Written by: 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/23/97 dpm Added keyHash(), used result to initialize 14 nybbleDex and queue. 15 12/18/97 dpm Improved queue initialization. 16 12/03/97 dpm Added queue lookahead; various optimizations. 17 11/13/97 dpm Created; broke out from comcryption.c 18 19 To Do: 20*/ 21 22#include "comcryptPriv.h" 23#include <stdio.h> 24#include <string.h> 25#include <stdlib.h> 26#ifdef macintosh 27#include <MacMemory.h> 28#endif 29 30/* if NULL, use our own */ 31comMallocExternFcn *comMallocExt = NULL; 32comFreeExternFcn *comFreeExt = NULL; 33 34#if COM_STATS 35comStats _comStats; 36 37void resetComStats() 38{ 39 memset(&_comStats, 0, sizeof(comStats)); 40} 41 42void getComStats(comStats *stats) 43{ 44 *stats = _comStats; 45} 46 47#else /*COM_STATS*/ 48 49#define incrComStat(stat, num) 50 51#endif /*COM_STATS*/ 52 53/* 54 * Generate a symbol permutation from the key. 55 */ 56void key_perm( 57 const unsigned char *key, 58 int keybytes, 59 unsigned char *map, 60 unsigned char *invmap) 61{ 62 int i, j, tmp, sum; 63 64 for(sum = 0, j = 0; j < keybytes; j++) { 65 sum += key[j]; 66 } 67 for(j=0; j < 256; j++) { 68 map[j] = j; 69 } 70 for(j=0; j < 255; j++) { 71 i = (key[j % keybytes] + j*sum) & 0xff; 72 tmp = map[i]; 73 map[i] = map[j]; 74 map[j] = tmp; 75 } 76 for(j=0; j<256; j++) { 77 invmap[map[j]] = j; 78 } 79} 80 81int keybyte( 82 const unsigned char *key, 83 int keybytes, 84 int index) 85{ 86 return((int) key[index % keybytes]); 87} 88 89int keynybble( 90 const unsigned char *key, 91 int keybytes, 92 int index) 93{ 94 int i = index % (2*keybytes); 95 int j; 96 97 j = key[i>>1]; /* Which byte. */ 98 if(i & 1) j >>= 4; /* Which nybble. */ 99 return(j & 0xf); 100} 101 102/* 103 * Hash a key array. 104 */ 105 106#define HASH_SEED 3 107#define HASH_REDUCE 1023 108 109static unsigned keyHash(const unsigned char *key, unsigned keylen) 110{ 111 unsigned x = HASH_SEED; /* Any seed in [1,p-1]. Like SEED = 3. */ 112 unsigned ctr; 113 114 for(ctr=0; ctr<keylen; ctr++) { 115 x = (x * (key[ctr] + (ctr & HASH_REDUCE) + 1)) % HASH_PRIME; 116 } 117 return x; 118} 119 120void mallocCodeBufs(comcryptBuf *cbuf) 121{ 122 /* 123 * calculate required buffer sizes. 124 * 125 * Assume max required codeBuf size is the max size of ciphertext needed 126 * to decrypt one block of plaintext. 127 */ 128 cbuf->codeBufSize = comcryptMaxOutBufSize(NULL, 129 CC_BLOCK_SIZE, 130 CCOP_COMCRYPT, 131 1); 132 cbuf->codeBuf = (unsigned char *)ascMalloc(cbuf->codeBufSize); 133 134 /* 135 * max size needed for level2Buf is the MaxOutBufSize of comcrypting 136 * a whole block of byte code. Note we assume that MaxOutBufSize(n) >= n. 137 */ 138 cbuf->level2BufSize = comcryptMaxOutBufSize(NULL, 139 MAX_TOKENS, // one byte per token 140 CCOP_COMCRYPT, 141 1); 142 cbuf->level2Buf = (unsigned char *)ascMalloc(cbuf->level2BufSize); 143 144 cbuf->queue = (queueElt *)ascMalloc(sizeof(queueElt) * QLEN); 145 146 #if QUEUE_LOOKAHEAD 147 /* 148 * Might want to do this dynamically, though that requires the malloc 149 * of the lookAhead buffer to be done in initCodeBufs(), not here (at 150 * comcryptAlloc() time). 151 * 152 * FIXME : should do the malloc of lookAhead buffer lazily for 153 * non-Mac platforms. 154 */ 155 cbuf->lookAhead = (unsigned char *)ascMalloc(LOOKAHEAD_SIZE); 156 #else /* QUEUE_LOOKAHEAD */ 157 cbuf->lookAhead = NULL; 158 #endif /* QUEUE_LOOKAHEAD */ 159 160 /* 161 * This maybe should also be done dynamically, lazily... 162 */ 163 cbuf->sigArray = (unsigned *)ascMalloc((MAX_TOKENS + 1) * sizeof(unsigned)); 164} 165 166void initCodeBufs( 167 comcryptBuf *cbuf, 168 const unsigned char *key, 169 unsigned keyLen, 170 unsigned char laEnable, 171 unsigned char sigSeqEnable) 172{ 173 unsigned ct; 174 unsigned qval; 175 unsigned char khash = (unsigned char)keyHash(key, keyLen); 176 177 cbuf->nybbleDex = khash; 178 179 if(laEnable) { 180 memset(cbuf->lookAhead, 0, LOOKAHEAD_SIZE); 181 } 182 183 laprintf(("initing queue and lookahead\n")); 184 185 for(ct=0; ct<QLEN; ct++) { 186 /* 187 * New queue init 23 Dec - init from khash 188 */ 189 unsigned short sbyte = ct ^ khash; 190 qval = (sbyte << 8) | ct; 191 cbuf->queue[ct] = qval; 192 if(laEnable) { 193 markInQueue(cbuf, qval, 1); 194 } 195 } 196 // note cbuf->nybbleDex = khash on return... 197 198 cbuf->f1 = F1_DEFAULT; 199 cbuf->f2 = F2_DEFAULT; 200 cbuf->jmatchThresh = THRESH_2LEVEL_JMATCH_DEF; 201 cbuf->minByteCode = THRESH_2LEVEL_NUMBYTECODES_DEF; 202 if(sigSeqEnable) { 203 initSigSequence(cbuf, key, keyLen); 204 } 205} 206 207void freeCodeBufs(comcryptBuf *cbuf) 208{ 209 if(cbuf->queue != NULL) { 210 ascFree(cbuf->queue); 211 } 212 if(cbuf->codeBuf != NULL) { 213 ascFree(cbuf->codeBuf); 214 } 215 if(cbuf->level2Buf != NULL) { 216 ascFree(cbuf->level2Buf); 217 } 218 if(cbuf->nextBuf != NULL) { 219 freeCodeBufs(cbuf->nextBuf); 220 ascFree(cbuf->nextBuf); 221 cbuf->nextBuf = NULL; 222 } 223 if(cbuf->lookAhead != NULL) { 224 ascFree(cbuf->lookAhead); 225 } 226 if(cbuf->sigArray != NULL) { 227 ascFree(cbuf->sigArray); 228 } 229} 230 231void serializeInt( 232 unsigned i, 233 unsigned char *buf) 234{ 235 buf[0] = (unsigned char)(i >> 24); 236 buf[1] = (unsigned char)(i >> 16); 237 buf[2] = (unsigned char)(i >> 8); 238 buf[3] = (unsigned char)(i & 0xff); 239} 240 241unsigned deserializeInt(unsigned char *buf) 242{ 243 unsigned i; 244 245 i = ((unsigned)buf[0]) << 24; 246 i |= ((unsigned)buf[1]) << 16; 247 i |= ((unsigned)buf[2]) << 8; 248 i |= buf[3]; 249 return i; 250} 251 252#if COM_PARAM_ENABLE 253 254unsigned getF1(comcryptObj cobj) 255{ 256 comcryptPriv *cpriv = (comcryptPriv *)cobj; 257 258 return cpriv->cbuf.f1; 259} 260 261void setF1(comcryptObj cobj, unsigned f1) 262{ 263 comcryptPriv *cpriv = (comcryptPriv *)cobj; 264 265 cpriv->cbuf.f1 = f1; 266 if(cpriv->cbuf.nextBuf != NULL) { 267 cpriv->cbuf.nextBuf->f1 = f1; 268 } 269} 270 271unsigned getF2(comcryptObj cobj) 272{ 273 comcryptPriv *cpriv = (comcryptPriv *)cobj; 274 275 return cpriv->cbuf.f2; 276} 277 278void setF2(comcryptObj cobj, unsigned f2) 279{ 280 comcryptPriv *cpriv = (comcryptPriv *)cobj; 281 282 cpriv->cbuf.f2 = f2; 283 if(cpriv->cbuf.nextBuf != NULL) { 284 cpriv->cbuf.nextBuf->f2 = f2; 285 } 286} 287 288unsigned getJmatchThresh(comcryptObj cobj) 289{ 290 comcryptPriv *cpriv = (comcryptPriv *)cobj; 291 292 return cpriv->cbuf.jmatchThresh; 293} 294 295void setJmatchThresh(comcryptObj cobj, unsigned jmatchThresh) 296{ 297 comcryptPriv *cpriv = (comcryptPriv *)cobj; 298 299 cpriv->cbuf.jmatchThresh = jmatchThresh; 300 if(cpriv->cbuf.nextBuf != NULL) { 301 cpriv->cbuf.nextBuf->jmatchThresh = jmatchThresh; 302 } 303} 304 305unsigned getMinByteCode(comcryptObj cobj) 306{ 307 comcryptPriv *cpriv = (comcryptPriv *)cobj; 308 309 return cpriv->cbuf.minByteCode; 310} 311 312void setMinByteCode(comcryptObj cobj, unsigned minByteCode) 313{ 314 comcryptPriv *cpriv = (comcryptPriv *)cobj; 315 316 cpriv->cbuf.minByteCode = minByteCode; 317 if(cpriv->cbuf.nextBuf != NULL) { 318 cpriv->cbuf.nextBuf->minByteCode = minByteCode; 319 } 320} 321 322#endif /*COM_PARAM_ENABLE*/ 323 324 325#if COM_LA_DEBUG 326 327/* 328 * Verify integrity of lookahead w.r.t. queue. 329 */ 330int testLookAhead(comcryptBuf *cbuf, int i1, int i2) 331{ 332 unsigned i; 333 334 if(!cbuf->laEnable) { 335 return 0; 336 } 337 for(i=0; i<QLEN; i++) { 338 if(!inQueue(cbuf, cbuf->queue[i])) { 339 printf("aaagh, corrupted lookahead - in queue[], !inQueue()\n"); 340 printf("i=0x%x i1=0x%x i2=0x%x\n", 341 i, i1, i2); 342 printf("\n"); 343 exit(1); 344 } 345 } 346 //return initTestLookAhead(cbuf); 347 return 0; 348} 349 350int initTestLookAhead(comcryptBuf *cbuf) 351{ 352 #if QUEUE_LOOKAHEAD_BIT 353 354 unsigned codeWord = 0; 355 unsigned char bit; 356 unsigned short byte; 357 unsigned char *la = cbuf->lookAhead; 358 359 for(byte=0; byte<LOOKAHEAD_SIZE; byte++) { 360 for(bit=1; bit!=0; bit<<=1) { 361 if(la[byte] & bit) { 362 /* 363 * in lookahead, make sure it's in queue[] 364 */ 365 int i; 366 int found = 0; 367 368 for(i=0; i<QLEN; i++) { 369 if(cbuf->queue[i] == codeWord) { 370 found = 1; 371 break; 372 } 373 } 374 if(!found) { 375 printf("***corrupted init lookahead - in l.a., " 376 "not in queue[]\n"); 377 printf("codeWord 0x%x\n", codeWord); 378 printf("\n"); 379 exit(1); 380 } 381 } 382 codeWord++; 383 } 384 } 385 386 #endif /* QUEUE_LOOKAHEAD_BIT */ 387 return 0; 388} 389 390#endif /* COM_LA_DEBUG */ 391 392void initSigSequence(comcryptBuf *cbuf, 393 const unsigned char *key, 394 unsigned keyLen) 395{ 396 unsigned seed = IN_OFFSET; 397 unsigned j; 398 399 for(j=0; j<keyLen; j++) { 400 seed += key[j]; 401 } 402 seed %= HASH_PRIME; 403 if(seed == 0) { 404 seed = IN_OFFSET; 405 } 406 cbuf->sigArray[0] = (unsigned short)seed; 407} 408 409#if 0 410/* 411 * Called once per token bit, after processing the token. 412 */ 413void nextSigWord(comcryptBuf *cbuf, 414 unsigned sigDex, // same as tokenDex 415 unsigned match, 416 unsigned above) // jabove, keyabove 417{ 418 unsigned offset; 419 unsigned short *sigArray = cbuf->sigArray; 420 421 #if COM_DEBUG 422 if(sigDex == 0) { 423 printf("nextSigWord underflow\n"); 424 exit(1); 425 } 426 if(sigDex > MAX_TOKENS) { 427 printf("nextSigWord overflow\n"); 428 exit(1); 429 } 430 #endif 431 432 if(match) { 433 offset = IN_OFFSET; 434 } 435 else { 436 offset = OUT_OFFSET; 437 } 438#if 1 439 sigArray[sigDex] = (sigArray[sigDex-1] * (above + offset)) % HASH_PRIME; 440#endif 441} 442#endif 443 444/* 445 * Obfuscate a block of ciphertext. 446 */ 447void sigMunge(comcryptBuf *cbuf, 448 const unsigned char *tokenPtr, 449 unsigned numTokens, 450 unsigned char *byteCodePtr, 451 unsigned char *longCodePtr) 452{ 453 unsigned char tokenBit = 0x01; 454 unsigned token; 455 unsigned short sig; 456 457 for(token=0; token<numTokens; token++) { 458 sig = cbuf->sigArray[token]; 459 if(*tokenPtr & tokenBit) { 460 /* no match - munge longCode - written MSB first */ 461 *longCodePtr++ ^= (unsigned char)(sig >> 8); 462 *longCodePtr++ ^= (unsigned char)sig; 463 } 464 else { 465 /* match - munge byteCode */ 466 *byteCodePtr++ ^= (unsigned char)sig; 467 } 468 tokenBit <<= 1; 469 if(tokenBit == 0) { 470 tokenBit = 0x01; 471 tokenPtr++; 472 } 473 } 474} 475 476 477/* 478 * All this can be optimized and tailored to specific platforms, of course... 479 */ 480 481void *ascMalloc(unsigned size) 482{ 483 #ifdef macintosh 484 485 Handle h; 486 OSErr err; 487 Ptr p; 488 489 #endif /* mac */ 490 491 if(comMallocExt != NULL) { 492 return (comMallocExt)(size); 493 } 494 495 #ifdef macintosh 496 497 h = nil; 498 err = errSecSuccess; 499 500 h = NewHandleSys(size); // system heap is not paged 501 do{ 502 HLockHi(h); // will move low in system heap 503 err = MemError(); 504 if( err != errSecSuccess ) break; 505 p = *h; 506 }while(0); 507 if( err != errSecSuccess ){ 508 return NULL; 509 } 510 return p; 511 512 #else /* others...*/ 513 return malloc(size); 514 #endif 515} 516 517void ascFree(void *data) 518{ 519 #ifdef macintosh 520 Handle h; 521 #endif 522 523 if(comFreeExt != NULL) { 524 (comFreeExt)(data); 525 return; 526 } 527 528 #ifdef macintosh 529 if( data != nil ){ 530 h = RecoverHandle((Ptr) data); 531 DisposeHandle(h); 532 } 533 534 #else /* others */ 535 free(data); 536 #endif 537} 538