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